Commit cc4fec8
Changed files (22)
build
product
client
boot
boot
container
presentation.windows
bootstrappers
commands
service.infrastructure
threading
commons
build/project.deploy.build
@@ -7,10 +7,12 @@
<property name="target" value="${log4net.config}" />
<call target="expand.template.file" />
<copy file="${build.config.dir}\log4net.config.xml" tofile="${product.dir}\client\boot\log4net.config.xml" />
+ <copy file="${build.config.dir}\log4net.config.xml" tofile="${product.dir}\client\presentation.windows\log4net.config.xml" />
<property name="target" value="${assembly.config}" />
<call target="expand.template.file" />
<copy file="${build.config.dir}\AssemblyInfo.cs" tofile="${product.dir}\client\boot\Properties\AssemblyInfo.cs" />
+ <copy file="${build.config.dir}\AssemblyInfo.cs" tofile="${product.dir}\client\presentation.windows\Properties\AssemblyInfo.cs" />
</target>
<target name="deploy" depends="create.configs, app.compile" />
product/client/boot/boot/container/WireUpTheContainer.cs
@@ -1,14 +1,13 @@
using Autofac.Builder;
using Gorilla.Commons.Infrastructure.Container;
using Gorilla.Commons.Infrastructure.Reflection;
-using gorilla.commons.infrastructure.thirdparty;
using gorilla.commons.infrastructure.thirdparty.Autofac;
using gorilla.commons.utility;
using MoMoney.boot.container.registration;
using momoney.database;
-using MoMoney.Domain.Accounting;
using MoMoney.Presentation;
using momoney.service.infrastructure;
+using Assembly = System.Reflection.Assembly;
namespace MoMoney.boot.container
{
@@ -30,14 +29,13 @@ namespace MoMoney.boot.container
.then(new WireUpTheViewsInToThe(registry))
.then(new WireUpTheReportsInToThe(registry))
.run_against(new ApplicationAssembly(
- System.Reflection.Assembly.GetExecutingAssembly(),
- typeof (DatabaseAssembly).Assembly,
- typeof (PresentationAssembly).Assembly,
- typeof (InfrastructureAssembly).Assembly
- ));
+ Assembly.GetExecutingAssembly(),
+ typeof (DatabaseAssembly).Assembly,
+ typeof (PresentationAssembly).Assembly,
+ typeof (InfrastructureAssembly).Assembly
+ ));
Resolve.initialize_with(registry.build());
}
}
-
}
\ No newline at end of file
product/client/presentation.windows/ComposeShell.cs → product/client/presentation.windows/bootstrappers/ComposeShell.cs
@@ -1,11 +1,8 @@
-using System.Threading;
-using System.Windows;
using System.Windows.Controls;
-using System.Windows.Controls.Primitives;
using presentation.windows.presenters;
using presentation.windows.views;
-namespace presentation.windows
+namespace presentation.windows.bootstrappers
{
public class ComposeShell : NeedStartup
{
@@ -28,21 +25,15 @@ namespace presentation.windows
region_manager.region<TabControl>(x => x.Items.Add(new TabItem {Header = "Liabilities"}));
region_manager.region<TabControl>(x => x.Items.Add(new TabItem {Header = "Budget"}));
- region_manager.region<StatusBar>(x => x.Items.Add(new Label {Content = Thread.CurrentPrincipal.Identity.Name}));
- region_manager.region<StatusBar>(x => x.Items.Add(new Label {Content = "Software Developer"}));
-
region_manager.region<MainMenu>(x =>
{
- x.add("_File").add("E_xit", () =>
- {
- Application.Current.Shutdown();
- });
- x.add("F_amily").add("_Add Member", () =>
+ x.add("_Family").add("_Add Member", () =>
{
controller.launch_dialog<AddFamilyMemberPresenter, AddFamilyMemberDialog>();
- MessageBox.Show("Add Family");
});
});
+
+ controller.load_region<StatusBarPresenter, StatusBarRegion>();
}
}
}
\ No newline at end of file
product/client/presentation.windows/commands/AddMemberToFamily.cs → product/client/presentation.windows/commands/AddFamilyMember.cs
@@ -1,14 +1,16 @@
+using System.Threading;
using Gorilla.Commons.Infrastructure.Logging;
using gorilla.commons.utility;
using presentation.windows.commands.dto;
namespace presentation.windows.commands
{
- public class AddMemberToFamily : ArgCommand<FamilyMemberToAdd>
+ public class AddFamilyMember : ArgCommand<FamilyMemberToAdd>
{
public void run_against(FamilyMemberToAdd item)
{
this.log().debug("adding family member");
+ Thread.Sleep(5000);
}
}
}
\ No newline at end of file
product/client/presentation.windows/commands/ContainerAwareParameterizedCommandBuilder.cs
@@ -1,6 +1,7 @@
using System;
using Gorilla.Commons.Infrastructure.Container;
using gorilla.commons.utility;
+using MoMoney.Service.Infrastructure.Eventing;
namespace presentation.windows.commands
{
@@ -8,18 +9,28 @@ namespace presentation.windows.commands
{
readonly T data;
Action action;
- string message;
- public ContainerAwareParameterizedCommandBuilder(T data)
+ EventAggregator event_broker;
+
+ public ContainerAwareParameterizedCommandBuilder(T data, EventAggregator event_broker)
{
this.data = data;
+ this.event_broker = event_broker;
}
public Command build<TCommand>(string message) where TCommand : ArgCommand<T>
{
- this.message = message;
action = () =>
{
+ event_broker.publish(new UpdateOnLongRunningProcess
+ {
+ message = message,
+ percent_complete = 0,
+ });
Resolve.the<TCommand>().run_against(data);
+ event_broker.publish(new UpdateOnLongRunningProcess
+ {
+ percent_complete = 100,
+ });
};
return this;
@@ -29,10 +40,5 @@ namespace presentation.windows.commands
{
action();
}
-
- public override string ToString()
- {
- return message;
- }
}
}
\ No newline at end of file
product/client/presentation.windows/commands/ContainerCommandBuilder.cs
@@ -1,13 +1,21 @@
using Gorilla.Commons.Infrastructure.Container;
using gorilla.commons.utility;
+using MoMoney.Service.Infrastructure.Eventing;
namespace presentation.windows.commands
{
public class ContainerCommandBuilder : CommandBuilder
{
+ EventAggregator event_aggregator;
+
+ public ContainerCommandBuilder(EventAggregator event_aggregator)
+ {
+ this.event_aggregator = event_aggregator;
+ }
+
public ParameterizedCommandBuilder<T> prepare<T>(T data)
{
- return new ContainerAwareParameterizedCommandBuilder<T>(data);
+ return new ContainerAwareParameterizedCommandBuilder<T>(data, event_aggregator);
}
public Command build<T>(string message) where T : Command
product/client/presentation.windows/commands/UpdateOnLongRunningProcess.cs
@@ -0,0 +1,10 @@
+using MoMoney.Service.Infrastructure.Eventing;
+
+namespace presentation.windows.commands
+{
+ public class UpdateOnLongRunningProcess : IEvent
+ {
+ public string message { get; set; }
+ public int percent_complete { get; set; }
+ }
+}
\ No newline at end of file
product/client/presentation.windows/presenters/AddFamilyMemberPresenter.cs
@@ -2,7 +2,6 @@ using System;
using MoMoney.Service.Infrastructure.Threading;
using presentation.windows.commands;
using presentation.windows.commands.dto;
-using presentation.windows.views;
namespace presentation.windows.presenters
{
@@ -28,7 +27,7 @@ namespace presentation.windows.presenters
last_name = last_name,
date_of_birth = date_of_birth
})
- .build<AddMemberToFamily>("Adding Family Member")
+ .build<AddFamilyMember>("Adding Family Member")
);
close();
});
product/client/presentation.windows/presenters/Observable.cs
@@ -0,0 +1,20 @@
+using System;
+using System.ComponentModel;
+using System.Linq.Expressions;
+using gorilla.commons.utility;
+
+namespace presentation.windows.presenters
+{
+ public abstract class Observable<T> : INotifyPropertyChanged
+ {
+ public event PropertyChangedEventHandler PropertyChanged = (o, e) => {};
+
+ protected void update(params Expression<Func<T, object>>[] properties)
+ {
+ properties.each(x =>
+ {
+ PropertyChanged(this, new PropertyChangedEventArgs(x.pick_property().Name));
+ });
+ }
+ }
+}
\ No newline at end of file
product/client/presentation.windows/presenters/StatusBarPresenter.cs
@@ -0,0 +1,27 @@
+using System.Threading;
+using MoMoney.Service.Infrastructure.Eventing;
+using presentation.windows.commands;
+
+namespace presentation.windows.presenters
+{
+ public class StatusBarPresenter : Observable<StatusBarPresenter>, Presenter, EventSubscriber<UpdateOnLongRunningProcess>
+ {
+ public string progress_message { get; set; }
+ public bool is_progress_bar_on { get; set; }
+ public string username { get; set; }
+ public string title { get; set; }
+
+ public void present()
+ {
+ username = Thread.CurrentPrincipal.Identity.Name;
+ title = "Software Developer";
+ }
+
+ public void notify(UpdateOnLongRunningProcess message)
+ {
+ progress_message = message.message;
+ is_progress_bar_on = message.percent_complete < 100;
+ update(x => x.progress_message, x => x.is_progress_bar_on);
+ }
+ }
+}
\ No newline at end of file
product/client/presentation.windows/views/ShellWIndow.xaml
@@ -4,16 +4,13 @@
<DockPanel VerticalAlignment="Stretch" HorizontalAlignment="Stretch">
<ui:MainMenu x:Name="Menu" DockPanel.Dock="Top">
</ui:MainMenu>
- <StatusBar Name="StatusBar" HorizontalAlignment="Right" DockPanel.Dock="Bottom">
- <Label>Test</Label>
- </StatusBar>
+ <ui:StatusBarRegion x:Name="StatusBar" DockPanel.Dock="Bottom"></ui:StatusBarRegion>
<StackPanel>
<Expander>
<Expander.Header>
<DockPanel>
<Label>Family Member:</Label>
<ComboBox Width="150"></ComboBox>
- <Button >Test</Button>
</DockPanel>
</Expander.Header>
<UniformGrid>
@@ -23,9 +20,7 @@
<Label>Khan</Label>
</UniformGrid>
</Expander>
- <TabControl Name="Tabs">
- <TabItem Header="Test"></TabItem>
- </TabControl>
+ <TabControl Name="Tabs"></TabControl>
</StackPanel>
</DockPanel>
</Window>
product/client/presentation.windows/views/ShellWIndow.xaml.cs
@@ -5,7 +5,7 @@ using gorilla.commons.utility;
namespace presentation.windows.views
{
- public partial class ShellWindow : Shell, RegionManager
+ public partial class ShellWindow : RegionManager
{
readonly IDictionary<Type, UIElement> regions;
product/client/presentation.windows/views/StatusBarRegion.xaml
@@ -0,0 +1,13 @@
+<UserControl x:Class="presentation.windows.views.StatusBarRegion"
+ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
+ <StatusBar HorizontalAlignment="Right">
+ <StatusBar.Resources>
+ <BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter" />
+ </StatusBar.Resources>
+ <Label Content="{Binding progress_message}"></Label>
+ <ProgressBar Width="200" Height="25" IsIndeterminate="True" Visibility="{Binding Path=is_progress_bar_on, Converter={StaticResource BooleanToVisibilityConverter}}"></ProgressBar>
+ <Label Content="{Binding username}"></Label>
+ <Label Content="{Binding title}"></Label>
+ </StatusBar>
+</UserControl>
product/client/presentation.windows/views/StatusBarRegion.xaml.cs
@@ -0,0 +1,12 @@
+using presentation.windows.presenters;
+
+namespace presentation.windows.views
+{
+ public partial class StatusBarRegion : View<StatusBarPresenter>
+ {
+ public StatusBarRegion()
+ {
+ InitializeComponent();
+ }
+ }
+}
\ No newline at end of file
product/client/presentation.windows/ApplicationController.cs
@@ -6,5 +6,6 @@ namespace presentation.windows
{
void add_tab<Presenter, Tab>() where Presenter : TabPresenter where Tab : FrameworkElement, Tab<Presenter>, new();
void launch_dialog<Presenter, Dialog>() where Presenter : DialogPresenter where Dialog : FrameworkElement, Dialog<Presenter>, new();
+ void load_region<Presenter, Region>() where Presenter : windows.Presenter where Region : FrameworkElement, View<Presenter>, new();
}
}
\ No newline at end of file
product/client/presentation.windows/presentation.windows.csproj
@@ -76,6 +76,10 @@
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
+ <Page Include="views\StatusBarRegion.xaml">
+ <SubType>Designer</SubType>
+ <Generator>MSBuild:Compile</Generator>
+ </Page>
<Compile Include="views\ShellWIndow.xaml.cs">
<DependentUpon>ShellWIndow.xaml</DependentUpon>
<SubType>Code</SubType>
@@ -84,16 +88,19 @@
<ItemGroup>
<Compile Include="ApplicationController.cs" />
<Compile Include="commands\ParameterizedCommandBuilder.cs" />
+ <Compile Include="commands\UpdateOnLongRunningProcess.cs" />
<Compile Include="Dialog.cs" />
<Compile Include="DialogPresenter.cs" />
<Compile Include="presenters\AddFamilyMemberPresenter.cs" />
<Compile Include="commands\CommandBuilder.cs" />
- <Compile Include="commands\AddMemberToFamily.cs" />
+ <Compile Include="commands\AddFamilyMember.cs" />
<Compile Include="presenters\CompensationPresenter.cs" />
<Compile Include="commands\dto\FamilyMemberToAdd.cs" />
<Compile Include="commands\ContainerCommandBuilder.cs" />
<Compile Include="commands\NamedCommand.cs" />
<Compile Include="commands\ContainerAwareParameterizedCommandBuilder.cs" />
+ <Compile Include="presenters\StatusBarPresenter.cs" />
+ <Compile Include="presenters\Observable.cs" />
<Compile Include="View.cs" />
<Compile Include="views\AddFamilyMemberDialog.xaml.cs">
<DependentUpon>AddFamilyMemberDialog.xaml</DependentUpon>
@@ -101,12 +108,11 @@
<Compile Include="views\CompensationTab.xaml.cs">
<DependentUpon>CompensationTab.xaml</DependentUpon>
</Compile>
- <Compile Include="ComposeShell.cs" />
+ <Compile Include="bootstrappers\ComposeShell.cs" />
<Compile Include="NeedStartup.cs" />
<Compile Include="Presenter.cs" />
<Compile Include="PresenterFactory.cs" />
<Compile Include="RegionManager.cs" />
- <Compile Include="Shell.cs" />
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs">
<SubType>Code</SubType>
@@ -127,6 +133,9 @@
<Compile Include="views\MainMenu.cs" />
<Compile Include="views\MenuItemExtensions.cs" />
<Compile Include="presenters\SimpleCommand.cs" />
+ <Compile Include="views\StatusBarRegion.xaml.cs">
+ <DependentUpon>StatusBarRegion.xaml</DependentUpon>
+ </Compile>
<Compile Include="WpfApplicationController.cs" />
<Compile Include="WpfPresenterFactory.cs" />
<EmbeddedResource Include="Properties\Resources.resx">
@@ -140,6 +149,10 @@
<AppDesigner Include="Properties\" />
</ItemGroup>
<ItemGroup>
+ <ProjectReference Include="..\..\commons\infrastructure.thirdparty.log4net\infrastructure.thirdparty.log4net.csproj">
+ <Project>{6BDCB0C1-51E1-435A-93D8-CA02BF8E409C}</Project>
+ <Name>infrastructure.thirdparty.log4net</Name>
+ </ProjectReference>
<ProjectReference Include="..\..\commons\infrastructure.thirdparty\infrastructure.thirdparty.csproj">
<Project>{04DC09B4-5DF9-44A6-8DD1-05941F0D0228}</Project>
<Name>infrastructure.thirdparty</Name>
@@ -157,6 +170,9 @@
<Name>service.infrastructure</Name>
</ProjectReference>
</ItemGroup>
+ <ItemGroup>
+ <Resource Include="log4net.config.xml" />
+ </ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
product/client/presentation.windows/Program.cs
@@ -1,12 +1,17 @@
using System;
using System.Collections.Generic;
+using System.ComponentModel;
using System.Security.Principal;
using System.Windows;
using Autofac.Builder;
using Gorilla.Commons.Infrastructure.Container;
+using Gorilla.Commons.Infrastructure.Logging;
using gorilla.commons.infrastructure.thirdparty.Autofac;
+using gorilla.commons.infrastructure.thirdparty.Log4Net;
using gorilla.commons.utility;
+using MoMoney.Service.Infrastructure.Eventing;
using MoMoney.Service.Infrastructure.Threading;
+using presentation.windows.bootstrappers;
using presentation.windows.commands;
using presentation.windows.presenters;
using presentation.windows.views;
@@ -32,21 +37,35 @@ namespace presentation.windows
{
var builder = new ContainerBuilder();
var shell_window = new ShellWindow();
- builder.Register(x => shell_window).As<RegionManager>();
+ builder.Register(x => shell_window).SingletonScoped();
+ builder.Register(x => shell_window).As<RegionManager>().SingletonScoped();
+ //needs startups
builder.Register<ComposeShell>().As<NeedStartup>();
- builder.Register<WpfApplicationController>().As<ApplicationController>();
- builder.Register<WpfPresenterFactory>().As<PresenterFactory>();
+ // infrastructure
+ builder.Register<Log4NetLogFactory>().As<LogFactory>().SingletonScoped();
+
+ // presentation infrastructure
+ builder.Register<WpfApplicationController>().As<ApplicationController>().SingletonScoped();
+ builder.Register<WpfPresenterFactory>().As<PresenterFactory>().SingletonScoped();
+ builder.Register<SynchronizedEventAggregator>().As<EventAggregator>().SingletonScoped();
+ builder.Register(x => AsyncOperationManager.SynchronizationContext);
+
+ // presenters
+ builder.Register<StatusBarPresenter>().SingletonScoped();
builder.Register<CompensationPresenter>();
builder.Register<AddFamilyMemberPresenter>();
- builder.Register<ContainerCommandBuilder>().As<CommandBuilder>();
- builder.Register<SynchronousCommandProcessor>().As<CommandProcessor>();
-
+ // commanding
+ builder.Register<ContainerCommandBuilder>().As<CommandBuilder>().SingletonScoped();
+ builder.Register<AsynchronousCommandProcessor>().As<CommandProcessor>().SingletonScoped();
+ builder.Register<AddFamilyMember>();
Resolve.initialize_with(new AutofacDependencyRegistryBuilder(builder).build());
Resolve.the<IEnumerable<NeedStartup>>().each(x => x.run());
+ Resolve.the<CommandProcessor>().run();
+
return shell_window;
}
}
product/client/presentation.windows/Shell.cs
@@ -1,4 +0,0 @@
-namespace presentation.windows
-{
- public interface Shell {}
-}
\ No newline at end of file
product/client/presentation.windows/WpfApplicationController.cs
@@ -1,5 +1,6 @@
using System.Windows;
using System.Windows.Controls;
+using MoMoney.Service.Infrastructure.Eventing;
using presentation.windows.views;
namespace presentation.windows
@@ -8,16 +9,19 @@ namespace presentation.windows
{
RegionManager region_manager;
PresenterFactory factory;
+ EventAggregator event_aggregator;
- public WpfApplicationController(RegionManager region_manager, PresenterFactory factory)
+ public WpfApplicationController(RegionManager region_manager, PresenterFactory factory, EventAggregator event_aggregator)
{
this.region_manager = region_manager;
+ this.event_aggregator = event_aggregator;
this.factory = factory;
}
public void add_tab<Presenter, View>() where Presenter : TabPresenter where View : FrameworkElement, Tab<Presenter>, new()
{
var presenter = factory.create<Presenter>();
+ event_aggregator.subscribe(presenter);
presenter.present();
region_manager.region<TabControl>(x => x.Items.Add(new TabItem
{
@@ -40,5 +44,16 @@ namespace presentation.windows
dialog.show_dialog(x);
});
}
+
+ public void load_region<Presenter, Region>() where Presenter : windows.Presenter where Region : FrameworkElement, View<Presenter>, new()
+ {
+ var presenter = factory.create<Presenter>();
+ event_aggregator.subscribe(presenter);
+ presenter.present();
+ region_manager.region<Region>(x =>
+ {
+ x.DataContext = presenter;
+ });
+ }
}
}
\ No newline at end of file
product/client/service.infrastructure/threading/AsynchronousCommandProcessor.cs
@@ -76,7 +76,6 @@ namespace MoMoney.Service.Infrastructure.Threading
});
safely_invoke(() =>
{
- this.log().debug("running command: {0}", command);
command.run();
});
reset_thread();
product/commons/utility/ExpressionExtensions.cs
@@ -0,0 +1,23 @@
+using System;
+using System.Linq.Expressions;
+using System.Reflection;
+
+namespace gorilla.commons.utility
+{
+ static public class ExpressionExtensions
+ {
+ static public PropertyInfo pick_property<T>(this Expression<Func<T, object>> expression)
+ {
+ return (PropertyInfo) member_expression(expression).Member;
+ }
+
+ static MemberExpression member_expression<T>(Expression<Func<T, object>> expression)
+ {
+ if (expression.Body.NodeType == ExpressionType.Convert)
+ return ((UnaryExpression) expression.Body).Operand as MemberExpression;
+ if (expression.Body.NodeType == ExpressionType.MemberAccess)
+ return expression.Body as MemberExpression;
+ throw new NotImplementedException();
+ }
+ }
+}
\ No newline at end of file
product/commons/utility/utility.csproj
@@ -58,6 +58,7 @@
<Compile Include="EmptyCallback.cs" />
<Compile Include="EmptyCommand.cs" />
<Compile Include="DefaultConstructorFactory.cs" />
+ <Compile Include="ExpressionExtensions.cs" />
<Compile Include="FactoryDelegate.cs" />
<Compile Include="FilteredVisitor.cs" />
<Compile Include="FuncSpecification.cs" />