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); }
Sunday, July 6, 2014
Testing Observables using NUnit/Moq in MVVM
Sunday, June 29, 2014
Use TPL/ TaskCompletionSouce to Implement DownloadAsync
Using Task create non-blocking, TaskCompletionSource SetResult helps send result accross
static void Main(string[] args)
{
Task<string> t = DownloadAsync();
Console.WriteLine("Do some other work while wating for Async Donwload");
Thread.Sleep(3000);
Console.WriteLine("other work done");
t.ContinueWith((t1) => { Console.WriteLine(t1.Result); });
// Task.WaitAny(new[] { t }); Wait =Readline to keep program running
// Console.WriteLine(t.Result);
Console.ReadLine();
}
static Task DownloadAsync()
{
TaskCompletionSource<string> ts = new TaskCompletionSource<string>();
string i="";
Task.Factory.StartNew(()=> { i = DownloadSync(); }).ContinueWith((t)=>
{ ts.SetResult(i); });
return ts.Task;
}
static string DownloadSync()
{
Thread.Sleep(5000);
return "Data";
}
Saturday, June 28, 2014
Convert Property Change to Observable
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); });
}
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; }
}
Subscribe to:
Posts (Atom)