What I do is use the Reactive Extensions framework for async work and it gives you the option to have the callbacks be called on the UI thread, like so:
var observable = DoSomeWork(); // returns IObservable, or you can use Observable.Start()
observable.ObserveOnDispatcher().Subscribe(_ => {}, error => {}, () => {});
All code within {} will be called on the UI thread and there you can do the NotifyPropertyChanged safely.
Worked for me until now, but I’m of course open to suggestions J
Adi
Freundliche Grüsse / Best regards
Adrian Hara
Cloud Developer
LinkedIn
coresystems ag
Villa im Park | Dorfstrasse 69
5210 Windisch | Switzerland
Phone +41 56 500 22 22
Fax +41 56 444 20 50
Infoline +41 848 088 088
www.coresystems.ch
www.coresuite.com
follow us on twitter
Visit us at CeBIT:
SAP Partner Booth: Hall 5, Booth A18
Cloud Computing: Hall 4, Booth A58
OS X Business Park: Hall 2, Booth A20
Microsoft Booth: Hall 4, Booth P47
The information transmitted is intended only for the person or entity to which it is addressed and may contain confidential and / or privileged material. Any review, retransmission, dissemination or other use of, or taking of any action in reliance upon, this information by persons or entities other than the intended recipient is prohibited. If you received this in error, please contact the sender and delete the material from any computer.
public interface ISchedulerContext
{
void Schedule(System.Action action);
}
[MapResource(typeof(ISchedulerContext), InstanceLifetime.Singleton)]
public class DispatcherContext : ISchedulerContext
{
public void Schedule(System.Action action)
{
System.Concurrency.Scheduler.Dispatcher.Dispatcher.BeginInvoke(action);
}
}
Dim
myComposer As CompositionServicemyComposer = New CompositionService
Dim var = Observable.Start(Sub() myComposer.Compose()) 'Run .Compuse async, which works
var.SubscribeOnDispatcher.Subscribe(
Sub()myLogMessages.Add(myComposer.LastMessage)
NotifyPropertyChanged(
Function() LogMessages) End Sub, Sub()NavigationService.Navigate(
New NavigationRequest("Pages/AdminRoot/")) End Sub)And inside CompositionService, they do some strange stuff with a 'Subject', but can't find a point to use this. As the notifications were fired on that 'Subject' object, and it is never used elswere, non of my target functions were fired ....
No documentation around, so it seems, that RX is not really supportet anymore.
With best regards
Gerhard
Public
Class ShellVM Inherits NavigationViewModelBase#Region
"Private Variables" Private myInstanceId As Guid Private myLogMessages As New List(Of String) Private myShowLoadProgressAction As Action(Of CompositionService) = Sub(o)myLogMessages.Add(o.LastMessage)
NotifyPropertyChanged(
Function() LogMessages) Debug.Print("ShellVM " & myInstanceId.ToString & " -- ShowLoadProgressAction fired at " & Now.TimeOfDay.ToString) End Sub Private myCompositionFinishedAction As Action = Sub() 'NavigationService.Navigate(New NavigationRequest("Pages/AdminRoot/")) Debug.Print("ShellVM " & myInstanceId.ToString & " -- CompositionFinishedAction fired at " & Now.TimeOfDay.ToString) End Sub#End
Region#Region
"Constructor(s)" Public Sub New()myInstanceId =
Guid.NewGuid Debug.Print("ShellVM " & myInstanceId.ToString & " -- New")myComposer =
New CompositionServicemyLogMessages.Add(
"Composing ...")NotifyPropertyChanged(
Function() LogMessages) ' just to demonstrate, that execution within the UI isn't blocked by composition 'NavigationService.Navigate(New NavigationRequest("Pages/AdminRoot/")) End Sub#End
Region Public ReadOnly Property LogMessages As IEnumerable(Of String) Get Return myLogMessages End Get End PropertyEnd
ClassAnd my sofisticated 'CompositionService' class:
Imports
System.ComponentModelPublic
Class CompositionService#Region
"Private Variables" Private ReadOnly mySubject As New Subject(Of CompositionService) Private myLastMessage As String#End
Region Public Sub Compose()myLastMessage =
"Three"mySubject.OnNext(
Me)System.Threading.
Thread.Sleep(10000)myLastMessage =
"Two"mySubject.OnNext(
Me)System.Threading.
Thread.Sleep(10000)myLastMessage =
"One"mySubject.OnNext(
Me)System.Threading.
Thread.Sleep(10000)myLastMessage =
"Liftoff"mySubject.OnNext(
Me)System.Threading.
Thread.Sleep(100)mySubject.OnCompleted()
End Sub Public ReadOnly Property NewsTicker As IObservable(Of CompositionService) Get Return mySubject.AsObservable End Get End Property Public ReadOnly Property LastMessage As String Get Return myLastMessage End Get End PropertyEnd
Class
Navigation fails also, but this is another task. First I want to have a simple listbox showing something like a countdown.
The real application should place version infos, infos about loaded extension moduls and whatever there.
With best regards
Gerhard
[MapService(typeof(IGenerateGameService), Lifetime = InstanceLifetime.PerInstance)]
public class GenerateGameService :
BackgroundWorker, IGenerateGameService
{
#region IGenerateGameService Members
public void GenerateGame(GameLevel level, Action<Game> gameCallback)
{
if (gameCallback == null) throw new ArgumentNullException("gameCallback");
RunWorkerAsync(new GameInfo()
{
GameLevel = level,
GameCallback = gameCallback
});
}
#endregion
#region Overrides
protected override void OnDoWork(DoWorkEventArgs e)
{
// create game
var _gameInfo = (GameInfo)e.Argument;
var _game = new Game() { Level = _gameInfo.GameLevel};
_game.NewGame();
_gameInfo.GameResult = _game;
// and return
e.Result = _gameInfo;
}
protected override void OnRunWorkerCompleted(RunWorkerCompletedEventArgs e)
{
var _gameInfo = (GameInfo)e.Result;
if (_gameInfo != null) _gameInfo.GameCallback(_gameInfo.GameResult);
}
#endregion
#region Nested Class
private class GameInfo
{
public GameLevel GameLevel { get; set; }
public Action<Game> GameCallback { get; set; }
public Game GameResult { get; set; }
}
#endregion
}
}
public interface IGenerateGameService
{
void GenerateGame(GameLevel level, Action<Game> gameCallback);
}
Quick question: lately I’ve been moving away from methods that take a “callback” parameter and writing them so they return an IObservable instead. I’ve found that this helps a lot in the long run if you ever need to compose multiple async calls. So far I haven’t seen an obvious flaw with this approach and can’t really think of a time when callbacks would be more appropriate. Am I missing something? J
Freundliche Grüsse / Best regards
Adrian Hara
Cloud Developer
LinkedIn
coresystems ag
Villa im Park | Dorfstrasse 69
5210 Windisch | Switzerland
Phone +41 56 500 22 22
Fax +41 56 444 20 50
Infoline +41 848 088 088
www.coresystems.ch
www.coresuite.com
follow us on twitter
Visit us at CeBIT:
SAP Partner Booth: Hall 5, Booth A18
Cloud Computing: Hall 4, Booth A58
OS X Business Park: Hall 2, Booth A20
Microsoft Booth: Hall 4, Booth P47
The information transmitted is intended only for the person or entity to which it is addressed and may contain confidential and / or privileged material. Any review, retransmission, dissemination or other use of, or taking of any action in reliance upon, this information by persons or entities other than the intended recipient is prohibited. If you received this in error, please contact the sender and delete the material from any computer.
From: nro...@googlegroups.com [mailto:nro...@googlegroups.com] On Behalf Of Rishi Oberoi
Sent: Wednesday, February 23, 2011 11:23 AM
To: nro...@googlegroups.com