(1) Install VS 2010 SP1 SDK (2) Tool -- Extension Manager, search VSPackage, install VSPackage Template and VSPackage Builder template (3) New Project, the Builder, Drag on "Add Toolbar" from toolbox, add two Combo, one button. Connect them to Group1. Now all will show up in Toolbar. Code to get Configuration Data from Server Http Endpoint--- must write in a seperate class file or Builder will overwrite it. class Configurator { public static string StartProjectName { get; private set; } public static void SetStartArguments(EnvDTE.DTE dte,string currEnvCombo, string currVerCombo) { foreach (Project p in dte.Solution.Projects) { if (p.Name == StartProjectName) p.ConfigurationManager.ActiveConfiguration.Properties.Item("StartArguments").Value = "env="+currEnvCombo+"\r\nver="+currVerCombo+"\r\nwebdata="+data; } } static string data = ""; public static void ReadConfigurationFromServer(ref string[] envArray, ref string[] verArray) { // Get Configuration from Server for all (env ver) and set two combo, start project etc. WebClient wc = new WebClient(); data = wc.DownloadString("http://www.cnn.com").Substring(300, 10); StartProjectName = "WpfApplication1"; envArray=new string[]{"UAT","LIVE","Local"}; verArray=new string[]{"Trading (London)","Trading (NYC)","Sales"}; } } public VSPackage1PackageBase() { Configurator.ReadConfigurationFromServer(ref envComboChoices, ref verComboChoices); } protected virtual void envComboExecuteHandler(object sender, EventArgs e) { ... Configurator.SetStartArguments(GetService(typeof(DTE)) as DTE, currentenvComboChoice, currentverComboChoice); Deployment: VSPackage project auto generate .vsix file for installation. But Do check vsixmanifest file "Select Editions" to include all VS.net 2010 editions
Monday, July 28, 2014
VS.Net Environment Configuration "Add-in" -- now called VS Package
Thursday, July 24, 2014
Practical MVVM/RX WPF App
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(); } }
Sunday, July 6, 2014
Producer Consumer Pattern with HandOff point
// Both Data Queue and Queue under SynchronizationContext allow handoff of data // Data Consumer can be parallel Enumerable or Subscribe to Observables // UI can only singled threaded Async or sync void BlockingCollectionAsQueue() { BlockingCollection<string> ServerData = new BlockingCollection<string>(10000); ServerData.Add("Data"); ServerData.CompleteAdding(); string data1; ServerData.TryTake(out data1, TimeSpan.FromMilliseconds(2)); IEnumerable<string> data = ServerData.GetConsumingEnumerable(); foreach (var v in data.AsParallel().AsOrdered().Select(l => Regex.Replace(l, @"\s+", ""))) ; } void UIMarshalling() { ThreadPool.QueueUserWorkItem((s) => { //do some server side work // UIControl.Invoke(); //Dispatcher.Invoke(); SendOrPostCallback spcb = new SendOrPostCallback((obj) => { }); // SynchronizationContext =WPF.Dispatcher or WF.Control.Invoke SynchronizationContext.Current.Send((state) => { //UI.Property=""; }, ""); }); }http://www.martinpersson.org/wordpress/2012/12/application-launcher/
TPL Fork Join code Pattern
// Count down until all 4 are signaled CountdownEvent ce = new CountdownEvent(4); ce.Signal(); ce.Wait(); // count up by add one for each work ce = new CountdownEvent(1); ce.AddCount(1); ce.Signal(); ce.Wait(); // Inlining -- Recursive Decomposition // walk by directly parallel void Walk2<T>(Tree<T> root, Action<T> action) { if (root == null) return; Parallel.Invoke( ()=> action(root.Data), () => Walk2(root.Left, action), () => Walk2(root.Right, action)); } //Continuation Chaining // Parallel <> Sum of Tasks, Unwrap() map Task<Task> to Task for Completion. if (root == null) return _CompletedTask; Task<Task> t2 = Task.Factory.StartNew(() => Walk(root.Left, action)); Task<Task> t3 = Task.Factory.StartNew(() => Walk(root.Right, action)); return Task.Factory.ContinueWhenAll(new Task[] { t1, t2.Unwrap(), t3.Unwrap() }, task => Task.WaitAll(task)); public static Task _CompletedTask = ((Func<Task>)(() => { TaskCompletionSource<object> ts = new TaskCompletionSource<object>(); ts.SetResult(null); return ts.Task; }))(); //Parallel with options: // option can cacell, set schedule, MaxDegree. // Parallel.For can be stoped by loop.Stop() inside For Parallel.Invoke(opts, () => { }, () => { }, () => { }); CancellationTokenSource ts = new CancellationTokenSource(); ParallelOptions opts = new ParallelOptions() { MaxDegreeOfParallelism = 2, TaskScheduler = TaskScheduler.FromCurrentSynchronizationContext(), CancellationToken = ts.Token }; ParallelLoopResult res = Parallel.For(0, 10000, () => 1, (j, loop, sub) => { if (loop.ShouldExitCurrentIteration) return 0; loop.Stop();
Testing Observables using NUnit/Moq in MVVM
Mock->setup a function must run for each parameter change. Obs.Create take in IObser and return IDispoable. So next a Subject to call OnNext. Note that Subject.sub(Obr) will allow OnNext to stream out Obs. Finally, testSchedule must advance to see data coming out. Mock_mockT= Mock ; _VMController = new(_mockT.Object, ...); [Test] public void IdChanged() { Id = new Hashset (){guid}; _mockT.Setup(p=>ObserveData(Id) .Return(GenerateObs(id:Id, data: 100.01)); Assert.AreEqual(_VMController.ViewModel.DataCollecton.Count,1); } IObs<PT> GenerateObs(string id="", double? data=null,DateTime logicalDate=null) { Data data = new (...); return Observable.Create(obsr=>{ // Func<IObserver,IDispoable> var s = new Subject<Data>(); s.subscribe(obsr); onNext<Data>(s,data); return s; }); } void onNext<T> (IObserver obr, T data) { obr.OnNext(data); _testSchedule.AdvancedBy(250ms); }
Subscribe to:
Posts (Atom)