INPC enable binding V <-> VM and need ICommand to execute request to Server side. It is interesting to see if Observables in Rx running on
a TaskPoolScheduler can do the same as Delagete or Relay Command. Both FromEventPattern and CLR event should work
public class ViewModel : INotifyPropertyChanged
{
public string Cusip { get; set; }
public double Ask { get;set; }
public event PropertyChangedEventHandler PropertyChanged;
public IObservable<Tuple<T, string>> OnSubmitChanges<T>(Expression<Func<ViewModel, T>> exp)
{
MemberExpression me = exp.Body as MemberExpression;
string n = me.Member.Name;
Func<ViewModel, T> f = exp.Compile();
T i = f.Invoke(this);
return Observable.Return(new Tuple<T,string>(i,n));
}
public ViewModel()
{
PropertyChanged += ViewModel_PropertyChanged;
// Observable.FromEventPattern<PropertyChangedEventHandler, PropertyChangedEventArgs>(hh => hh.Invoke, h => this.PropertyChanged += h, h => this.PropertyChanged -= h)
.Subscribe((e) => { ViewModel_PropertyChanged(this, e.EventArgs); });
}
private void ViewModel_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
// From Event Pattern does not need subscribe again. Direct call Server side is enougth.
if (e.PropertyName == "Cusip")
OnSubmitChanges(vm => vm.Cusip).Subscribe((i) => { Console.WriteLine("Call IVMController->IModObsAdapter->IModObsTransport->QueueAsObserver " + i); }); //459200-10-1 //912828NB2
if (e.PropertyName == "Ask")
OnSubmitChanges(vm => vm.Ask).Subscribe((i) => { Console.WriteLine("Hit bid lift offer " + i); });
}
}
private static void TestConvertPropChangeToObservable()
{
ViewModel v = new ViewModel();
v.Cusip = "912828NB2";
v.OnSubmitChanges(vm => vm.Cusip).Subscribe((i) => { Console.WriteLine("Call IVMController->IModObsAdapter->IModObsTransport->QueueAsObserver " + i); }); //459200-10-1 //912828NB2
v.Ask = 98.23;
v.OnSubmitChanges(vm => vm.Ask).Subscribe((i) => { Console.WriteLine("Hit bid lift offer " + i); });
}
Saturday, June 28, 2014
Convert Property Change to Observable
Sunday, June 22, 2014
F# Async through Agent= inbox as Queue
Agent are mailbox and can run async block, similar to run a async block inside a function.
open System
open System.Net
open Microsoft.FSharp.Control.WebExtensions
open System.Diagnostics
open System.IO
let urlList= ["cnn" , "http://www.cnn.com"
"china", "http://www.china.com"
]
let fetch( url :string) =
let uri = new Uri(url)
let c = new WebClient()
let html =c.DownloadString(uri)
printfn "%s" html
let fetchAsync(n: string, url :string) =
async {
let uri = new Uri(url)
let c = new WebClient()
let! html =c.AsyncDownloadString(uri)
printfn "%s" html
}
let runAsync() =
urlList
|> Seq.map fetchAsync
|> Async.Parallel
|> Async.RunSynchronously
let runSync() =
"http://www.cnn.com"
|> fetch
let s= new StreamWriter("c:\working\1.txt",true)
s.AutoFlush <-true
let agent =
MailboxProcessor.Start( fun inbox ->
async { while true do
let! msg =inbox.Receive()
// fetch(msg)
s.WriteLine(DateTime.Now.ToString()+ " "+msg);
})
[]
let main arg =
runSync()
fetch("http://www.cnn.com")
runAsync() |> ignore
agent.Post("http://www.cnn.com")
agent.Post("http://www.china.com")
agent.Post("http://www.goolge.com")
agent.Post("http://www.fb.com")
let mutable b=true
let mutable n=1
Console.ReadLine() |> ignore
while b do
n<-n+1
if n>1000 then
b <-false
agent.Post(n.ToString())
Console.ReadLine() |> ignore
s.Close()
0
Tuesday, April 22, 2014
Generate Observables
class Program
{
static void Main(string[] args)
{
DateTime dtStart = DateTime.Now;
var txns = GenerateObservable<Transaction>(3, dt => new Transaction() { id = "txn " + dt.ToString() }, 3, dt => dt < dtStart.AddSeconds(120));
var bsds = GenerateObservable<Transaction>(1, dt => new BondStaticData() { id = "bsd " + dt.ToString() }, 3, dt => dt < dtStart.AddSeconds(10));
txns.CombineLatest(bsds,(t,b)=> t.id+" "+b.id).Subscribe(s=>Console.WriteLine(s));
Console.ReadLine();
}
static IObservable GenerateObservable<T>(int seconds4Iteration, Func<DateTime,T> newT, int nextInSeconds,Func<DateTime,bool> continuation)
{
DateTime dtStart = DateTime.Now;
return Observable.Generate(dtStart, continuation, dt => dt.AddSeconds(seconds4Iteration), newT, dt => TimeSpan.FromSeconds(nextInSeconds));
}
}
Tuesday, March 18, 2014
Await a Task Completion Source Task for Async Data
The following can be modified to use yield return and observables
private async void Button_Click(object sender, RoutedEventArgs e)
{
await Test();
}
Task
{
WebClient w = new WebClient();
return w.DownloadStringTaskAsync("");
}
Task
{
var tcs = new TaskCompletionSource
WebClient w = new WebClient();
w.DownloadStringCompleted +=
(_, args) =>
{
tcs.SetResult(args.Result);
};
return tcs.Task;
}
Thursday, November 14, 2013
Context Menu style must be applied to MenuItem Level by ItemContainerStyle to avoid delegate command bind to the same target
Context Menu style must be applied to MenuItem Level by ItemContainerStyle
Using TextBox.ContextMenu will create two instances of the style s1 so it will not bind only one textbox by Multiple binding.
<TextBox HorizontalAlignment="Left" Height="30" Margin="10,554,0,0" TextWrapping="Wrap" Text="TextBox" VerticalAlignment="Top" Width="211" Name="tb1" >
<TextBox.ContextMenu>
<ContextMenu ItemsSource="{Binding Mode=OneWay,Path=SelectorData}" ItemContainerStyle="{StaticResource s1}"></ContextMenu>
</TextBox.ContextMenu>
</TextBox>
<Style TargetType="MenuItem" x:Key="s1">
<Setter Property="ItemsSource" Value="{Binding SubSelectorData}"></Setter>
<Setter Property="Header" Value="{Binding Name}"></Setter>
<Setter Property="Tag" Value="{Binding ReturnValue}"></Setter>
<Setter Property="Command" Value="{Binding SelectorCommand}"></Setter>
<Setter Property="CommandParameter">
<Setter.Value>
<MultiBinding Converter="{StaticResource multiSenderTarget2CmdParamConv}">
<Binding RelativeSource="{RelativeSource FindAncestor, AncestorType={x:Type TextBox}}"></Binding>
<Binding RelativeSource="{RelativeSource Self}"></Binding>
</MultiBinding>
</Setter.Value>
</Setter>
</Style>
public List<SelectorData> SelectorData { get; set; }
SelectorService svc = new SelectorService();
svc.SelectorCommandAll = new DelegateCommand<object>((p) =>
{
Tuple<object, object> t = p as Tuple<object, object>;
TextBox tb = t.Item1 as TextBox;
MenuItem mi = t.Item2 as MenuItem;
tb.Text = mi.Tag.ToString() + ";" + mi.Header.ToString();
});
public class MutipleSenderTargetToCommandParameterConverter : System.Windows.Data.IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (values.Length == 1) return new Tuple<object>(values[0]);
if (values.Length == 2) return new Tuple<object, object>(values[0], values[1]);
<Style x:Key="ssOnlyOneInstanceNotWorking" TargetType="{x:Type TextBox}" >
<Setter Property="TextBox.ContextMenu" >
<Setter.Value>
<ContextMenu ItemsSource="{Binding Mode=OneWay,Path=SelectorData}" ItemContainerStyle="{StaticResource s1}"></ContextMenu>
</Setter.Value>
</Setter>
</Style>
public class SelectorData
{
public string Name { get; set; }
public List<SelectorData> SubSelectorData { get; set; }
public bool HasSubSelectorData { get; set; }
public int Level { get; set; }
public DelegateCommand<object> SelectorCommand { get; set; }
public string ReturnValue { get; set; }
}
Thursday, September 26, 2013
Self Arrange Top Windows
WPF Desktop App can Popup multiple full size windows randomly and confuse users. So it is useful to create a list storing these windows and arrange their display as One Full size with all other as thumbnail hanging to the side.The following code implement what is shown in the screen shot. Note this assume one dispatcher due to threading issues. i.e all windows must pop up from on dispatcher.
Code for a window self arrange:
using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Diagnostics; using System.Linq; using System.Reactive.Linq; using System.Text; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Shapes; namespace WpfApplication1 { /// <summary> /// Interaction logic for Window1.xaml /// </summary> public partial class Window2 : Window { #region declaration public IObservable<System.Reactive.EventPattern<EventArgs>> WindowLocationChangedRxEventArgs { get; set; } public IObservable<System.Reactive.EventPattern<MouseButtonEventArgs>> WindowMouseDownRxEventArgs { get; set; } public IObservable<System.Reactive.EventPattern<MouseEventArgs>> HeaderPreviewMouseMoveRxEventArgs { get; set; } public bool SwitchInProgress { get; set; } public static SortedList<DateTime, Window2> TopWindowList { get; set; } public Guid ID { get; set; } public DateTime AddedAt { get; set; } public static Point LocationOfArrangement { get; set; } #endregion #region Contructor public Window2() { InitializeComponent(); WindowStyle = System.Windows.WindowStyle.None; ResizeMode = System.Windows.ResizeMode.NoResize; ID = Guid.NewGuid(); AddedAt = DateTime.Now; AddToList(); ToolTip = ID.ToString(); #region Event to Rx Observable WindowLocationChangedRxEventArgs = from evt in Observable.FromEventPattern<EventHandler, EventArgs>(h => this.LocationChanged += h, h => this.LocationChanged -= h) select evt; WindowLocationChangedRxEventArgs.Subscribe(evt => { Window2 w = evt.Sender as Window2; if (w.IsFullSize && !w.SwitchInProgress) { LocationOfArrangement = new Point(w.Left, w.Top); w.ArrangeDisplay(); } if (w.SwitchInProgress) w.SwitchInProgress = false; }); WindowMouseDownRxEventArgs = from evt in Observable.FromEventPattern<MouseButtonEventHandler, MouseButtonEventArgs>(h => MouseDown += h, h => MouseDown -= h) select evt; WindowMouseDownRxEventArgs.Subscribe(evt => { Window2 w = evt.Sender as Window2; if (w.IsFullSize) return; SwitchInProgress = true; ArrangeDisplay(true); }); HeaderPreviewMouseMoveRxEventArgs = from evt in Observable.FromEventPattern<MouseEventHandler, MouseEventArgs>(h => header.PreviewMouseMove += h, h => header.PreviewMouseMove -= h) select evt; HeaderPreviewMouseMoveRxEventArgs.Subscribe(evt => { if (evt.EventArgs.LeftButton == MouseButtonState.Pressed) { DragMove(); } }); #endregion t1.Text = "Just for Identication: " + ID + " " + AddedAt.ToString(); t2.Text = "Managed Thread Id " + System.Threading.Thread.CurrentThread.ManagedThreadId; } static Window2() { TopWindowList = new SortedList<DateTime, Window2>(); LocationOfArrangement = new Point(300, 300); } #endregion #region List public void RemoveFromListById(Guid id) { var w= TopWindowList.FirstOrDefault(_=>_.Value.ID==id); TopWindowList.Remove(w.Key); } public void AddToList() { Window2 w = (from _ in TopWindowList.Values where _.ID == this.ID select _).FirstOrDefault(); if (w == null) { TopWindowList.Add(AddedAt, this); } } #endregion #region Arrange public void ArrangeDisplay(bool MakeMeFullSize = false) { ArrangeSize(MakeMeFullSize); ArrangeLocaton(); ToggleContent(); } #endregion #region Content public void ShowFullContent() { v.Visibility = System.Windows.Visibility.Collapsed; g.Visibility = System.Windows.Visibility.Visible; } public void ShowSmallContent() { v.Visibility = Visibility.Visible; g.Visibility = System.Windows.Visibility.Collapsed; } private void ToggleContent() { foreach (var t in TopWindowList.Values) { if (t.IsFullSize) t.ShowFullContent(); else t.ShowSmallContent(); } } #endregion #region Location private void ArrangeLocaton() { Window2 prevThumbnail = null; TopWindowList.OrderBy(_ => _.Key); for (int i = 0; i < TopWindowList.Values.Count;i++ ) { var t = TopWindowList.Values[i]; if (t.IsFullSize) { t.Top = LocationOfArrangement.Y; t.Left = LocationOfArrangement.X; } else { if (prevThumbnail == null) { t.Top = LocationOfArrangement.Y; t.Left = LocationOfArrangement.X - t.Width - 2; } else { double d1 = 0; double d2 = 0; d1 = prevThumbnail.Top + prevThumbnail.Height; d2 = prevThumbnail.Left; t.Top = d1 + 2; t.Left = d2; } prevThumbnail = t; } } } #endregion #region Sizing private bool IsFullSize { get; set; } private void ShowFullSize() { ResizeMode = System.Windows. ResizeMode.CanResize; Width = 300; Height = 300; ResizeMode = System.Windows.ResizeMode.NoResize; IsFullSize = true; } private void ShowThumbnailSize() { ResizeMode = System.Windows.ResizeMode.CanResize; Width = 50; Height = 50; ResizeMode = System.Windows.ResizeMode.NoResize; IsFullSize = false; } private void ArrangeSize(bool MakeMeFullSize = false) { if (MakeMeFullSize) foreach (var t in TopWindowList.Values) { if (t.ID == this.ID) t.ShowFullSize(); else t.ShowThumbnailSize(); } else { var q = (from _ in TopWindowList.Values where _.IsFullSize select _).FirstOrDefault(); if (q == null && TopWindowList.Values.Count > 0) { TopWindowList.OrderBy(_ => _.Key); TopWindowList.Values[0].ArrangeDisplay(true); } if(q!=null) { if (q.ID != ID) { ShowThumbnailSize(); } } } } #endregion } }Xaml code
<Window x:Class="WpfApplication1.Window2" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Window2" Height="300" Width="300" BorderBrush="Gray" BorderThickness="1" ShowInTaskbar="False"> <Grid> <Grid Name="g"> <Grid.RowDefinitions> <RowDefinition Height="21*"/> <RowDefinition Height="111*"/> <RowDefinition Height="95*"/> <RowDefinition Height="40*"/> </Grid.RowDefinitions> <Grid.ColumnDefinitions> <ColumnDefinition Width="150" MinWidth="144"/> <ColumnDefinition Width="150" MinWidth="148"/> </Grid.ColumnDefinitions> <Rectangle Name="header" Fill="Gray" Grid.Row="0" HorizontalAlignment="Left" Height="20" Stroke="Black" VerticalAlignment="Top" Width="292" Grid.Column="0" Grid.ColumnSpan="2" /> <TextBox Name="t1" Height="101" Margin="10,0,18,0" Grid.Row="1" TextWrapping="Wrap" AcceptsReturn="True" Text="TextBox" VerticalAlignment="Top" Grid.Column="0" Grid.ColumnSpan="2"/> <TextBox Name="t2" Height="89" Margin="10,4,18,0" Grid.Row="2" TextWrapping="Wrap" Text="TextBox" VerticalAlignment="Top" Grid.Column="0" Grid.ColumnSpan="2"/> <Button Content="Send" Grid.Row="3" Grid.Column="1" Margin="10,4,17,6"/> <Button Content="Close" Grid.Row="3" Grid.Column="0" Margin="10,4,10,6"/> </Grid> <Viewbox Name="v" Visibility="Collapsed" > <StackPanel> <TextBlock TextWrapping="Wrap" >Thumbnail Content </TextBlock> <TextBlock TextWrapping="Wrap" >Small Size Shrinkable</TextBlock> </StackPanel> </Viewbox> </Grid> </Window>Code To Simulate Windows Mutiple PopUp
private void Button_Click(object sender, RoutedEventArgs e) { Observable.Interval(TimeSpan.FromSeconds(3)).Subscribe((t) => { Dispatcher.Invoke(() => { Window2 w = new Window2() { }; w.Show(); w.ArrangeDisplay(); }); }); }
Saturday, September 14, 2013
Directly Accessing Dispatcher from Observables may freeze UI
The following code made UI not responsive, can not move either main or popup windows.
It seems that directly hitting dispatcher can overwhelm it. Consider using BlockingCollection.
// Observer Popup window every 5 seconds. e.g. RFQ and its updates come in during peak market hours.
private void Button_Click(object sender, RoutedEventArgs e)
{
Observable.Interval(TimeSpan.FromSeconds(5)).Subscribe((t)=>
{
this.Dispatcher.Invoke(() => { (new Window1() { Title = t.ToString() }).Show(); });
// this.Dispatcher.BeginInvoke(new Action(() => { (new Window1() { Title = t.ToString() }).Show(); })); // same behavior
});
// each window may take long time to PopUp during data delay or binding on UI Thread.
public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
Thread.Sleep(5000); // simulating delay on UI Thread.
}
}
One solution is to use multiple dispatchers
private void Button_Click_1(object sender, RoutedEventArgs e)
{
Observable.Interval(TimeSpan.FromSeconds(5)).Subscribe((t) =>
{
Thread th = new Thread(new ThreadStart(show));
th.SetApartmentState(ApartmentState.STA);
th.IsBackground = true;
th.Start();
});
}
void show()
{
Windows w= new Window1() { Title = DateTime.Now.ToString() });
w.Show();
w.Closed += (sender2, e2) =>
w.Dispatcher.InvokeShutdown();
System.Windows.Threading.Dispatcher.Run();
}
Subscribe to:
Posts (Atom)
