Updating UI in batches with RX c# - c#

I'm having an issue with updating WPF UI with the RX. Currently I have a class that has an event which is called within its functions. Event is subscribed from the UI thread and updates the UI like below :
SomeClass.cs
public partial class SomeClass
{
public delegate Task ProgressUpdate(string value);
public delegate Task BarUpdate(int value);
public event ProgressUpdate OnProgressUpdateList;
public event BarUpdate OnProgressUpdateBar;
public async Task DoSomething()
{
// execute code
<some code>
// update UI
if (OnProgressUpdateList != null)
{
OnProgressUpdateList(update);
}
}
}
And in MainWindow.xaml
var someClass = new SomeClass();
someClass.OnProgressUpdateList += Export_OnProgressUpdateList;
someClass.OnProgressUpdateBar += Export_OnProgressUpdateBar;
private async Task Export_OnProgressUpdateList(string text)
{
await Dispatcher.InvokeAsync(() =>
{
OutputLog.AppendText(text);
OutputLog.AppendText(Environment.NewLine);
OutputLog.ScrollToEnd();
});
}
This code works except the program processes huge number of files and I'm assuming this is why the UI becomes frozen very quickly (I see the updates being done in the first half a second). I searched for a way around this and I came into a solution to use RX for batching the UI calls. I've searched through several SO posts but I couldn't find an answer on how to correctly implements this (or convert C# events to RX observables) when I call those events from the class and subscribe to this event from outside that class. Can someone help me understand this?

I'm posting an answer to myself as I couldn't get one here and I finally figured it out so for anyone looking for that in the future - here you go:
public partial class SomeClass {
public Subject<string> outputLogSubject = new Subject<string>();
public IObservable<string> OutputLog => outputLogSubject.AsObservable();
//Add string for collection updating UI
outputLogSubject.OnNext(string);
//After finishing the work you can call outputLogSubject.OnCompleted() to stop buffering
outputLogSubject.OnCompleted();
}
It needs to be added in the class that will be calling the executing the work.
Below needs to be added in the UI thread after initialization and BEFORE processing work :
var buffer = someClass.OutputLog.Buffer(TimeSpan.FromMilliseconds(1000), 6);
var chunked = buffer.ObserveOnDispatcher(DispatcherPriority.Background);
var update = chunked.Subscribe(name =>
{
foreach (var item in name)
{
OutputLog.AppendText(item);
}
OutputLog.ScrollToEnd();
});
This allowed me to keep the UI responsive to the point of seeing the output log is real time

Related

How to make a strong publisher in c#?

In c#,we normally make publisher like below:
public class Publisher
{
public event Action NotifySomethingEvent;
public void RaiseNotifySomethingEvent()
{
NotifySomething?.Invoke();
}
}
while the subscriber has define a method like this:
public void HandlerSomething()
{
Thread.Sleep(2000);
}
This subscriber would cause the publisher thread blocking.
Do there anyway to fix this issue?
By the way,the publisher BeginInvoke method will cause the subscriber execute time confuse,so is not in consideration.
the subscriber execute time confuse means:
class Program
{
static void Main(string[] args)
{
Publisher publisher = new Publisher();
SubScriber subscriber = new SubScriber();
publisher.NotifySomething += subscriber.HandlerSomething;
publisher.RaiseNotifySomething();
publisher.RaiseNotifySomething();
publisher.RaiseNotifySomething();
Console.ReadKey();
}
}
public class Publisher
{
public event Action NotifySomething;
public void RaiseNotifySomething()
{
NotifySomething?.Invoke();
}
}
public class SubScriber
{
int d = 0;
ReaderWriterLock locker = new ReaderWriterLock();
public void HandlerSomething()
{
d += 1;
Action<int> action = new Action<int>((t) =>
{
Thread.Sleep(100);
Console.WriteLine(t);
});
action.BeginInvoke(d, null, null);
}
}
}
the upper code expect result is : 1 2 3
but in fact it result is random,like 1,3,2 1,2,3 or 3,2,1
Apparently you do not want the subscribers to block the publishing thread but do want them to be executed in published order.
You could enqueue your published events and have another thread dequeue these events in order and wait for the subscribers to finish their job.
Building this can get dirty so I recommend you find a Pub-Sub library you feel comfortable with.
I would recommend the MassTransit project. It works async. It has queues. Additionally, you can put the concern of orchestrating the events into a workflow (called a Saga), whicht might come in handy when your project gets more complex.
I am unaware of the complexity of your project. MassTransit supports RabbitMQ but also in-memory as the transport layer. So it scales very well.
It is already done and is called ReactiveExtensions.
It implements IObservable interface which can publish events and you can subscribe to them. It also covers end of events and errors. Take a look.
There even is MVVM framework based on them called ReactiveUI

How to dispatch work among several processors?

I have a class wich performs some data processing:
class Processor
{
public Processor() {
// Load lot of data
}
public string GetResult(string input) {
// ...
}
}
I need to implement a service wich exposes HTTP API to this class. I use Owin and Microsoft.AspNet.* libs to host HTTP Web API. For each request it creates a new thread to handle it, but I cannot instantiate Processor on every request as it takes enormous time to load some data in its constructor. Also I cannot reuse one instance from different threads as it was not designed to be thread safe. But I can instantiate several instances of Processor on service start, and then dispatch work among them. Say I allow up to 20 concurrent HTTP requests for my service. I create 20 instances of Processor and add Busy flag to the class:
class Processor
{
public bool Busy { get; set; }
// ...
}
I wrote Dispatcher class like this:
class Dispatcher
{
readonly Processor[] _processors;
readonly SemaphoreSlim _semaphore;
public Dispatcher(int maxProcessors)
{
_semaphore = new SemaphoreSlim(maxProcessors);
_processors = new Processor[maxProcessors];
// Instantiate Processors, etc...
}
public string GetResult(string input)
{
try
{
_semaphore.Wait(); // Surplus requests will wait here.
Processor processor;
lock (_processors)
{
// It is guaranteed that such processor exists if we entered the semaphore.
processor = _processors.First(p => !p.Busy);
processor.Busy = true;
}
var result = processor.GetResult(input);
processor.Busy = false;
return result;
}
finally
{
_semaphore.Release();
}
}
}
Then I can basically call it through Dispatcher in ApiController:
public class ServiceController : ApiController
{
static Dispatcher _dispatcher = new Dispatcher(20);
[Route("result")]
[HttpGet]
public string Result(string input)
{
return _dispatcher.GetResult(input);
}
}
Is it implemented correctly for my purpose?
I tested it and it works, but I wonder if I reinvented the wheel and .NET Framework has somewhat ready to use for my case, or if it could be implemented easier.
Basically in your class that is going to be run in the thread, create an event and event handler. The object that then spins up this task can register to that event. When it is raised by the task, (in this case you would raise the event when it is done) you can do something, ie. give it more work.
Create your events in the class that will be run in the child thread:
public event TaskCompleteEventHandler OnComplete;
public event TaskErrorEventHandler OnError;
Register to your events in the object that is spinning up the classes:
task.OnComplete += TaskComplete;
task.OnError += TaskComplete;
Create the function in the calling class that will handle the event:
public void TaskComplete()
{
//give the thread more work
}

How to implement async INotifyPropertyChanged

I have a class with properties that are bound to my view. To keep my view up-to-date, I implement INotifyPropertyChanged and raise the event everytime some property changes.
Now I got some heavy functions that freeze my application. I want to put them into a background task.
First: here my current approach
(e.g. on button click)
private async void HeavyFunc()
{
foreach (var stuff)
{
count += await Task.Run(() => stuff.Fetch());
}
if (count == 0)
//...
}
stuff class
public async Task<int> Fetch()
{
//network stuff
RaisePropertyChanged("MyProperty");
}
public async void RaisePropertyChanged(string pChangedProperty)
{
await Application.Current.Dispatcher.BeginInvoke(
System.Windows.Threading.DispatcherPriority.Normal,
new ThreadStart(() =>
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(pChangedProperty);
}
);
}
The code above gives an exception ("DependencySource" must be created in the same thread like "DependencyObject").
AFAIK, you generally need to create a new thread and run it (while awaiting it). ´await Task.Run(...);´ should do this job.
Since the PropertyChanged event directly influences the UI, calling it in the UI thread seems to be a good decision. This is why I call Dispatcher.BeginInvoke.
What I don't understand: the exception above is caused when different threads are responsible for the data. But I explicitely calling the event on my UI-thread and the object should be created by the UI-thread too. So why do I get an exception?
My main question is: How do I implement the events for the INotifyPropertyChanged interface generally to avoid or handle most of the async programming problems like above? What should be considered while constructing the functions?
Now I got some heavy functions that freeze my application.
If you're really doing asynchronous "network stuff", then it shouldn't be freezing the app.
My main question is: How do I implement the events for the INotifyPropertyChanged interface generally to avoid or handle most of the async programming problems like above?
The approach that I prefer is to not handle this in the event raising code. Instead, structure the rest of your code so that it respects the UI layer.
In other words, divide your "service" (or "business logic") code from your "UI" code so that it works like this:
// In StuffService class:
public async Task<Result> FetchAsync()
{
//network stuff
return result;
}
// In StuffViewModel class:
public async void ButtonClicked()
{
foreach (var stuff)
{
var result = await Task.Run(() => _stuffService.FetchAsync());
MyProperty = result.MyProperty;
count += result.Count;
}
if (count == 0)
//...
}
public Property MyProperty
{
get { return _myProperty; }
set
{
_myProperty = value;
RaisePropertyChanged();
}
}
private void RaisePropertyChanged([CallerMemberName] string pChangedProperty = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(pChangedProperty));
}
This way, there's no manual thread jumping, all properties have the standard ViewModel implementation, the code is simpler and more maintainable, etc.
I did leave in the call to Task.Run, although this should be superfluous if your network calls are truly asynchronous.

Dynamically updating a WPF Window before code finishes executing

This is probably a really basic question, please bear with me, I'm still very new to the world of WPF/C#.
I have a WPF app where I open a new window if a button is clicked.
The window is called Sync and all it does is instantiate a viewmodel class which contains some public properties that are bound to my view.
The viewmodel also instantiates a class containing a lot of business logic, this updates the ViewModel's bound properties, the aim being to update the content of my window.
This sort of works, but only when all of the (sometimes quite lengthy) processing is completed does the window load and the view is populated with the last value of the ViewModel's properties.
I think I'm missing something pretty basic here. How do I get my window to instantly load and then have the view update when any of the properties have changed? Should I be listening for a PropertyChanged event and then updating the view? Where do i do this? Within the view model's setter?
Here's some simplified code:
Calling my window from my main window's View Model
public void SyncAction()
{
Sync syncWindow = new Sync();
syncWindow.Show();
syncWindow.Activate();
}
The window
public partial class Sync : Window
{
public Sync()
{
InitializeComponent();
var viewModel = new SyncViewModel();
}
}
The view model
class SyncViewModel
{
private string _miscStatus = "";
public SyncViewModel()
{
var sync = new SyncLogic();
sync.SyncAll(this);
}
public string MiscStatus
{
get
{
return _miscStatus;
}
set
{
_miscStatus += value;
}
}
}
Some business logic
class SyncLogic
{
private ViewModel.SyncViewModel _syncViewModel;
public void SyncAll(ViewModel.SyncViewModel syncViewModel)
{
_syncViewModel = syncViewModel;
// lock our synctime
var syncTime = DateTools.getNow();
_syncViewModel.MiscStatus = "Sync starting at " + syncTime.ToString();
// Do lots of other stuff
_syncViewModel.MiscStatus = String.Format("Sync finished at at {0}, total time taken {1}",
DateTools.getNow().ToString(), (DateTools.getNow() - syncTime).ToString());
}
}
Bonus question: The way I'm updating the view from within my business logic (by passing in a reference to the viewmodel and updating its properties from there) seems a bit kludgy. I definitely want to keep the business logic separate, but am not sure how I can pass any output back out to the viewmodel. What would be a better way of doing this please?
Why do you care whether the update takes visual effect before or after the code finishes executing? The internal properties are updated immediately; any code that queries the UI will see the new values.
The only time the user will be able to perceive a difference between an update during execution vs after execution is if you have a long-running computation on the UI thread. Don't do that.
Instead, run the computation asynchronously with the UI, so that repaint messages can be processed meanwhile. You can do this using a background thread, but the new easier way with C# 4 and later is async. Because async is implemented using continuation messages to the UI thread, you don't need to synchronize data access or marshal UI access between threads. It just works, and very well. The only thing you need to do is to break your code into small enough chunks, each implemented as an async method, that you don't cause noticeable delay.
What I would do:
Don't do any heavy logic in the ViewModel constructor. Constructor should only initialize object and do nothing else. In your example, constructor should be empty.
public SyncViewModel()
{
}
SyncLogic should not be aware of the ViewModel. Introduce some other class to communicate input arguments and sync results. Let's say SyncArguments and SyncResult.
class SyncLogic
{
public SyncResult SyncAll(SyncArguments syncArgs)
{
var syncResult = new SyncResult();
// Do lots of other stuff
// populate syncResult
return syncResult;
}
}
Introduce a method in the viewmodel that should be called to do the "sync" logic, and make that method async. That way it's very easy to do the heavy stuff in the background and leave the UI thread to do the job it should do, draw the UI.
public async Task Sync()
{
// lock our synctime
var syncTime = DateTools.getNow();
MiscStatus = "Sync starting at " + syncTime.ToString();
var sync = new SyncLogic();
var syncArgs = new SyncArguments();
//populate syncArgs from ViewModel data
//call the SyncAll as new Task so it will be executed as background operation
//and "await" the result
var syncResults = await Task.Factory.StartNew(()=>sync.SyncAll(syncArgs));
//when the Task completes your execution will continue here and you can populate the
//ViewModel with results
MiscStatus = String.Format("Sync finished at at {0}, total time taken {1}",
DateTools.getNow().ToString(), (DateTools.getNow() - syncTime).ToString());
}
Make the button click event handler that creates and shows the window async, so you can call Sync method on the ViewModel
private void async Button_click(object sender, EventArgs e)
{
Sync syncWindow = new Sync();
var viewModel = new SyncViewModel();
syncWindow.DataContext = viewModel;
syncWindow.Show();
syncWindow.Activate();
await viewModel.Sync();
}
That will draw the Window without waiting on the Sync method. When the Sync taks completes, viewmodel properties will be populated from the SyncResult and the Bindings will draw them on screen.
Hope you get the idea, sorry if there are some errors in my code, not sure that it all compiles.
First, make sure to set the viewmodel as the view's DataContext:
public partial class Sync : Window
{
public Sync()
{
InitializeComponent();
var viewModel = new SyncViewModel();
DataContext = viewModel;
}
}
Second, you'll have to run the "sync" stuff on a background thread. This is easiest with the async+await keywords in .Net 4.5:
public async void SyncAll(ViewModel.SyncViewModel syncViewModel)
{
_syncViewModel = syncViewModel;
// lock our synctime
var syncTime = DateTools.getNow();
_syncViewModel.MiscStatus = "Sync starting at " + syncTime.ToString();
await Task.Factory.StartNew(() => {
// Do lots of other stuff
});
_syncViewModel.MiscStatus = String.Format("Sync finished at at {0}, total time taken {1}",
DateTools.getNow().ToString(), (DateTools.getNow() - syncTime).ToString());
}
With databinding your Window will automatically updated as long as it notified that properties it bound to has been changed. So what you need is implement INotifyPropertyChanged in the viewmodel and raise property changed event whenever binding source property value changed. For example:
public class SyncViewModel : INotifyPropertyChanged
{
private string _miscStatus = "";
public string MiscStatus
{
get{ return _miscStatus; }
set
{
_miscStatus += value;
OnPropertyChanged("MiscStatus");
}
}
#region INotifyPropertyChanged implementation
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
#endregion
}
In case somebody else comes across this issue in WPF, the solution described here is really simple and just worked fine for me. It uses an extension method to force an UIElement to be rendered:
public static class ExtensionMethods
{
private static Action EmptyDelegate = delegate() { };
public static void Refresh(this UIElement uiElement)
{
uiElement.Dispatcher.Invoke(DispatcherPriority.Render, EmptyDelegate);
}
}
Then, simply use as:
private void SomeLongOperation()
{
// long operations...
// UI update
label1.Content = someValue;
label1.Refresh();
// continue long operations
}
}
Quoting the original author:
The Refresh method is the extension method that takes any UI element and then calls that UIElement's Dispatcher's Invoke method. The trick is to call the Invoke method with DispatcherPriority of Render or lower. Since we don't want to do anything, I created an empty delegate. So how come this achieves refresh functionality?
When the DispatcherPriority is set to Render (or lower), the code will then execute all operations that are of that priority or higher. In the example, the code already sets label1.Content to something else, which will result in a render operation. So by calling Dispatcher.Invoke, the code essentially asks the system to execute all operations that are Render or higher priority, thus the control will then render itself (drawing the new content). Afterwards, it will then execute the provided delegate (which is our empty method).

Calling a void async. - Event based pattern, or another method?

I have a class that basically stores files in amazon s3.
Here is what it looks like (simplified)
public class S3FileStore
{
public void PutFile(string ID, Stream content)
{
//do stuff
}
}
In my client app, I want to be able to call:
var s3 = new() S3FileStore();
s3.PutFile ("myId", File.OpenRead(#"C:\myFile1"));
s3.PutFile ("myId", File.OpenRead(#"C:\myFile2"));
s3.PutFile ("myId", File.OpenRead(#"C:\myFile3"));
I want this to be an asynchronous operation - I want the S3FileStore to handle this (i don't want my caller to have to execute PutFile asynchronously so to speak) but, i want to be able to trap exceptions / tell if the operation completed for each file.
I've looked at event based async calls, especially this:
http://blogs.windowsclient.net/rendle/archive/2008/11/04/functional-shortcuts-2-event-based-asynchronous-pattern.aspx
However, I can't see how to call my PutFile (void) method?
Are there any better examples?
Look at the solution for this question: Adding cancel ability and exception handling to async code . Hope it helps.
The BackgroundWorker base class might be worth a look, and also the Thread Pool:
ThreadPool.QueueUserWorkItem(delegate
{
s3.PutFile ("myId", File.OpenRead(#"C:\myFile1"));
});
This is basically what you would do with the Action/BeginInvoke pattern. With BeginInvoke, you additionally receive an IAsyncResult on which you can call .WaitOne() to block the current thread until the operation finished, in case you need that. You would trigger a new BeginInvoke for every file you'd like to save.
If you need to do this frequently, a more sophisticated version could be to use a Queue in combination with the BackgroundWorker, e.g.:
public sealed class S3StoreLikePutFileWorker<TYourData> : BackgroundWorker
{
private AutoResetEvent WakeUpEvent = new AutoResetEvent(false);
private Queue<TYourData> DataQueue = new Queue<TYourData>();
private volatile bool StopWork = false;
public void PutFile(TYourData dataToWrite)
{
DataQueue.Enqueue(dataToWrite);
WakeUpEvent.Set();
}
public void Close()
{
StopWork = true;
WakeUpEvent.Set();
}
private override void OnDoWork(DoWorkEventArgs e)
{
do
{
// sleep until there is something to do
WakeUpEvent.WaitOne();
if(StopWork) break;
// Write data, if available
while(DataQueue.Count > 0)
{
TYourData yourDataToWrite = DataQueue.Dequeue();
// write data to file
}
}
while(!StopWork);
}
}
Depending on how much complexity you need.
The BackgroundWorker supports progress feedback (set WorkerReportsProgress = true; in the constructor), and you can also add a custom event to report errors, if that is necessary:
// create a custom EventArgs class that provides the information you need
public sealed class MyEventArgs : EventArgs {
// Add information about the file
}
// ... define the event in the worker class ...
public event EventHandler<MyEventArgs> ErrorOccured;
// ... call it in the worker class (if needed) ...
if(ErrorOccured != null) ErrorOccured(this, new MyEventArgs(/*...*/));

Categories