Building MVVM/Rx WPF need to glue together multiple interface and correctly hand off to Dispatcher:
(1) (engineering) Need to use nuget.config align with .sln so package managed at solution level
<add key="repositorypath" value="Packages" />
(2) (design pattern) View - ViewModel --VMController--Adapter -- Transport
(3) (engineering) Fluent API can easily glue DataContext to VM, VMController point to VM
public class FluentFactory
{
public FluentFactory ViewModelController(Func<IViewModelController> viewModelControllerFactory)
{
var f = viewModelControllerFactory.Invoke();
f.ViewModel = _viewModel;
return this;
}
INotifyPropertyChanged _viewModel=null;
public FluentFactory ViewModel(Func<INotifyPropertyChanged> viewModelFactory)
{
_viewModel = viewModelFactory.Invoke();
return this;
}
public void View(Func<FrameworkElement> viewFactory)
{
FrameworkElement fe = viewFactory.Invoke();
fe.DataContext = _viewModel;
}
}
(4) (MVVM) Module can resolve instance to inject into DockingViewManager
public class TradingModule : IModule
{
IUnityContainer _container;
public TradingModule(IUnityContainer container)
{
_container = container;
}
public void Initialize()
{
_container.RegisterInstance<ITransport>(new TradingTransport());
_container.RegisterInstance<IAdapter>(new TradingAdapter());
_container.RegisterInstance<IScheduler>(new NewThreadScheduler());
_container.RegisterInstance<LocalScheduler>(DispatcherScheduler.Current);
}
}
(5) (Rx) DockingViewManager will Create VMController when Button Click ask for well known view and then start Observable sequence
public class DockingViewManager : IDockingViewManager
{
public DockingViewManager(ITransport transport, IAdapter adapter, IScheduler scheduler, LocalScheduler dispatcher)
public UserControl GetDockingView(WellknowViewName viewName)
{
FluentFactory f = new FluentFactory();
if (viewName == WellknowViewName.DurationTraderView)
{
DurationTraderView durView = new DurationTraderView();
f.ViewModel(() => new DurationTraderViewModel())
.ViewModelController(() => CreateDurationTraderViewModelController())
.View(() => durView);
return durView;
}
if (viewName == WellknowViewName._5_10Yr)
{
_5_10YRView view = new _5_10YRView();
f.ViewModel(() => new _5_10YRViewModel())
.ViewModelController(() => Create_5_10YRViewModelController())
.View(() => view);
return view;
}
return new UserControl();
}
public DurationTraderViewModelController CreateDurationTraderViewModelController()
{
return new DurationTraderViewModelController(_transport,_adapter,_scheduler,_dispatcher);
}
}
public class DurationTraderViewModelController : IViewModelController
{
public INotifyPropertyChanged ViewModel { get; set; }
public DurationTraderViewModelController(ITransport transport, IAdapter adapter, IScheduler scheduler, LocalScheduler dispatcher)
{
transport.GetTradingObservables()
.SubscribeOn(scheduler)
.ObserveOn(dispatcher)
.Subscribe(fSet => adapter.updater(fSet, ViewModel));
}
}
public class TradingTransport : ITransport
{
public IObservable<IFieldDataSet> GetTradingObservables()
{
return Observable.Create<IFieldDataSet>((obsr) =>
{
return Observable.Timer(TimeSpan.Zero, TimeSpan.FromSeconds(1)).Select(i => new FieldDataSet()).Subscribe(obsr);
});
}
}
Side Note--- OnPropertyChange("Cusip") is error prone with Hard-coded string. Better utilize Expression tree in C# 4.0
SetProperty(ref _cusip, value,()=>Cusip);
public void SetProperty<T>(ref T field, T value, Expression<Func<T>> exp)
{
if (EqualityComparer<T>.Default.Equals(field, value)) return;
field = value;
if (PropertyChanged != null)
{
MemberExpression me = exp.Body as MemberExpression;
if (me != null && me.Member != null)
PropertyChanged(this, new PropertyChangedEventArgs(me.Member.Name));
}
}
Side Note --- Load Module by Config
<modules>
<module assemblyFile="Modules.dll"
moduleType="Modules.TradingModule, Modules, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"
moduleName="TradingModule" startupLoaded="true" />
</modules>
public class DemoUnityBootstrapper : UnityBootstrapper
{
protected override IModuleCatalog CreateModuleCatalog()
{
return new ConfigurationModuleCatalog();
}
}
Thursday, July 24, 2014
Practical MVVM/RX WPF App
Subscribe to:
Post Comments (Atom)
No comments:
Post a Comment