Sorry I still don't understand how UI works and what is Dispatcher
I have such DispatchingWcfModel:
public interface IWcfModel
{
List<ConsoleData> DataList { get; set; }
event Action<List<ConsoleData>> DataArrived;
}
class DispatchingWcfModel : IWcfModel
{
private readonly IWcfModel _underlying;
private readonly Dispatcher _currentDispatcher;
public DispatchingWcfModel(IWcfModel model)
{
_currentDispatcher = Dispatcher.CurrentDispatcher;
_underlying = model;
_underlying.DataArrived += _underlying_DataArrived;
}
private void _underlying_DataArrived(List<ConsoleData> obj)
{
Action dispatchAction = () =>
{
if (DataArrived != null)
{
DataArrived(obj);
}
};
_currentDispatcher.BeginInvoke(DispatcherPriority.DataBind, dispatchAction);
}
public List<ConsoleData> DataList
{
get { throw new NotImplementedException(); }
set { throw new NotImplementedException(); }
}
public event Action<List<ConsoleData>> DataArrived;
}
Now I want to add int[] ConnectionStats { get; set; }. Should I introduce separate event for it? What should I write in DispatchingWcfModel? I want to have interface like that:
public interface IWcfModel
{
List<ConsoleData> DataList { get; set; }
int[] ConnectionStats { get; set; }
event Action<List<ConsoleData>> DataArrived;
}
The Dispatcher is WPF's internal message queue for the main UI Thread. It can be used from other threads to run commands on the main UI thread of an application.
This is important because WPF doesn't let you access objects which were created on other threads. For example, if a Button is created on the main UI thread, then you cannot modify this button from another thread, but you can use the Dispatcher from another thread to send a command to the main UI thread to update the button.
This applies to all objects, not just UI Elements. If something like an ObservableCollection is created on one thread, another thread cannot modify it. Because of this, all objects are usually created on the main UI thread.
Dispatcher messages can get processed synchronously or asynchronously, and they can have different priorities . In your code, you're using _currentDispatcher.BeginInvoke(DispatcherPriority.DataBind, dispatchAction);, which means it will begin an asynchronous operation with the main UI thread, and run it at the same priority as DataBinding. You can view more information on DispatcherPriorities here.
If your ConnectionStats collection gets its data asynchronously, then you will want to add some kind of DataArrived method that will take data obtained from a non-UI thread and add it to the collection. You can use the existing DataArrived method if the data is obtained and packaged together, or create your own if the data is obtained separately. If it gets it's data synchronously, you don't need to do anything special.
From the looks of things, _underlying_DataArrived is meant to run on a background thread (meaning it can't alter your collections, which should be created on the main UI thread), while DataArrived is meant to run on the main UI thread.
Related
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
I'm struggling with NotifyCollectionChangedAction.Reset on a separate thread.
I have the following class which overrides the ObservavbleCollection so that I can suspend notifications when doing bulk updates. In the constructor I also make a call to support modifying the collection on different thread using BindingOperations.EnableCollectionSyncronization
The issue I have is when doing the NotifyCollectionChangedAction.Reset not on the UI thread I get an exception (regular Add/Remove to the collection work). I thought BindingOperations.EnableCollectionSyncronization enabled cross thread notifications?
public class ObservableDataCollection<T> : ObservableCollection<T>
{
private bool _suppressNotification = false;
private object _lock = new object();
public ObservableDataCollection(IEnumerable<T> collection) : base(collection) { BindingOperations.EnableCollectionSynchronization(Items, _lock); }
public ObservableDataCollection() { BindingOperations.EnableCollectionSynchronization(Items, _lock); }
protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
{
if (!_suppressNotification)
base.OnCollectionChanged(e);
}
protected override void OnPropertyChanged(PropertyChangedEventArgs e)
{
if (!_suppressNotification)
base.OnPropertyChanged(e);
}
public void SuppressNotifications(bool suppressNotification)
{
_suppressNotification = suppressNotification;
if (_suppressNotification == false)
base.OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
}
}
Then when I make changes
// On UI thread
var synchronizedCollection = new ObservableDataCollection();
BindingOperations.EnableCollectionSynchronization(synchronizedCollection, synchronizedCollection.SyncLock);
// Background thread
syncronizedCollection.SupressNotifications(true);
synchronizedCollection.Clear();
synchronizedCollection.Add/Remove etc
syncronizedCollection.SupressNotifications(false); // throws
I had assumed that BindingOperations.EnableCollectionSynchronization would take care of dispatching base.OnCollectionChanged in my SupressNotifications call on the UI thread.
So I need to take care of dispatching it on the UI thread.
I know I have to call BindingOperations.EnableCollectionSynchronization` from each UI thread.
The bigger question then becomes what happens and how do I manage notifications when the collection is bound on multiple UI threads?
As I have said before, the method BindingOperations.EnableCollectionSynchronization must be called on the thread that the CollectionView of ObservableDataCollection is associated with.
CollectionView has Dispatcher affinity, which is the root of all problems and the reason you must marshal theINotifyCollectionChanged handler invocation to the correct Dispatcher thread. Taking care of this should fix your problem.
The fact that you are calling BindingOperations.EnableCollectionSynchronization in the constructor may also be a reason that lead to the issue.
Consider a scenario, where the instance of the collection is created on a different thread than it is actually used: you are going to experience a cross-thread exception. It's best practice to let the user of your class handle this.
Another important point is that BindingOperations.EnableCollectionSynchronization is only applied to the CollectionView of the collection passed as the argument. This means you are currently synchronizing the view of the internal collection Items. This is not the view that is returned when setting up a Binding that has the owning ObservableDataCollection as Binding.Source. You are synchronizing the wrong collection view and must synchronize ObservableDataCollection instead:
public ObservableDataCollection()
=> BindingOperations.EnableCollectionSynchronization(this, _lock);
But since you should remove the call to BindingOperations.EnableCollectionSynchronization from the constructor and should expose the sync lock object:
public class ObservableDataCollection<T> : ObservableCollection<T>
{
public object SyncLock { get; } = new object();
private bool _suppressNotification = false;
public ObservableDataCollection(IEnumerable<T> collection) : base(collection) {}
public ObservableDataCollection() {}
}
, the proper way to mark the collection as synchronized would be:
// On UI thread
var synchronizedCollection = new ObservableDataCollection();
BindingOperations.EnableCollectionSynchronization(synchronizedCollection, synchronizedCollection.SyncLock);
// Background thread
synchronizedCollection.Clear(); // Won't throw
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
}
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).
In my multi threaded apps i need to do cross thread access on UI elements and i am using the thread safe methods to do that. I am repeatedly using this a lot in many of my projects and keeping them in the form file itself is making the file look ugly. So i want to create a seprate class where i can put all this and call them whenever needed but i am having trouble with it. For instace for changing the text element of a control i am using the following
delegate void SetTextCallback(string text, Control ctrl);
public void SetText(string text, Control ctrl)
{
if (ctrl.InvokeRequired)
{
SetTextCallback d = new SetTextCallback(SetText);
this.Invoke(d, new object[] { text, ctrl });
}
else
{
if (ctrl.GetType() == typeof(Label))
{
ctrl.Text = text;
}
else
{
ctrl.Text += Environment.NewLine + text;
}
}
}
and call this function as
SetText("some text",label1);
This works fine if it is in the form class, if i put it into another class i am getting an error in the line
this.Invoke(d, new object[] { text, ctrl });
Can some one tell me how can i do this properly.
Also is it possible to have one UI accessor method do all the stuff, that is right now i am having multiple methods like this one to change the text one to change the enabled property one to change the back color and one to change the fore color. Is it possible to do it with something like
public void ChangePropert(Control ctrl,Property prop,Value val)
The problem with all this is you are starting to leak UI code outside of the form where the controls actually reside. A thread should not have to know about controls, it should do work and update the main thread and let the main thread worry about what needs to be done in the UI.
The way to accomplish this is have a callback that a second thread can call, but force that callback to actually be executed on the main thread instead of executed on the second thread. You can accomplish this by using the Synchronization context.
You need to wrap your secondary threads in a class that can keep a reference to the main thread synchronization context. Then the secondary threads can use this for call backs.
Example:
public partial class Form1 : Form
{
private SynchronizationContext _synchronizationContext;
public Form1()
{
InitializeComponent();
//Client must be careful to create sync context somehwere they are sure to be on main thread
_synchronizationContext = AsyncOperationManager.SynchronizationContext;
}
//Callback method implementation - must be of this form
public void ReceiveThreadData(object threadData)
{
// This callback now exeutes on the main thread.
// Can use directly in UI without error
this.listBoxMain.Items.Add((string)threadData);
}
private void DoSomeThreadWork()
{
// Thread needs callback and sync context so it must be wrapped in a class.
SendOrPostCallback callback = new SendOrPostCallback(ReceiveThreadData);
SomeThreadTask task = new SomeThreadTask(_synchronizationContext, callback);
Thread thread = new Thread(task.ExecuteThreadTask);
thread.Start();
}
private void button1_Click(object sender, EventArgs e)
{
DoSomeThreadWork();
}
}
And your thread class will look something like this:
/// SomeThreadTask defines the work a thread needs to do and also provides any data ///required along with callback pointers etc.
/// Populate a new SomeThreadTask instance with a synch context and callnbackl along with ///any data the thread needs
/// then start the thread to execute the task.
/// </summary>
public class SomeThreadTask
{
private string _taskId;
private SendOrPostCallback _completedCallback;
private SynchronizationContext _synchronizationContext;
/// <summary>
/// Get instance of a delegate used to notify the main thread when done.
/// </summary>
internal SendOrPostCallback CompletedCallback
{
get { return _completedCallback; }
}
/// <summary>
/// Get SynchronizationContext for main thread.
/// </summary>
internal SynchronizationContext SynchronizationContext
{
get { return _synchronizationContext; }
}
/// <summary>
/// Thread entry point function.
/// </summary>
public void ExecuteThreadTask()
{
//Just sleep instead of doing any real work
Thread.Sleep(5000);
string message = "This is some spoof data from thread work.";
// Execute callback on synch context to tell main thread this task is done.
SynchronizationContext.Post(CompletedCallback, (object)message);
}
public SomeThreadTask(SynchronizationContext synchronizationContext, SendOrPostCallback callback)
{
_synchronizationContext = synchronizationContext;
_completedCallback = callback;
}
}
Now you can just get rid of all the invoke crap on every control.
You could separate this stuff out as Extension methods. That would allow you to call methods in the object itself instead of passing it in as a parameter like you do now.
So you could do: label1.SetText("some text"); instad of SetText("some text", label1);
An additional gain would be that you could have separate implementations for each control type, so you could have one for label and one for the text box. This would make the code somewhat cleaner.
Finally, regarding your question about using reflection to set the properties. You can get a reference to the property using the Type.GetProperty() method. This returns a PropertyInfo object that you can use to set the property value like this:
var textProperty = label1.GetType().GetProperty("Text");
textProperty.SetValue(label1, "some text", null);
It is just while you debugging your project, right?
anyway, if you had another option not to create a separate class to manipulate this, you can set this CheckForIllegalCrossThreadCalls property to false on each form that calls threads other than its own thread.
CheckForIllegalCrossThreadCalls - MSDN