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