I'm using an MVC pattern in winforms application. I need to call remote service asynchronously. So On some event in View I invoke corresponding Presenter method. In Presenter I call BeginInvoke method of service. But to View must be updated only in Main Thread. I could actualy point CallBack to some function in View, and update it`s controls state, but this conflicts with MVP pattern - View must not be responsible for data it carries. This callback function must be in Presenter. But how then invoke View in Main Thread?
Put the callback function in the presenter. Have the presenter call whatever update function on the view is required/have the view observe the presenter's state and handle the 'completed' event. In the view's function, if the view is implemented by a windows Form, test the InvokeRequired property to see if the call has come in on the windows thread. If it hasn't, then use Invoke to invoke it instead.
private void SetMessage(string message)
{
if (InvokeRequired)
{
BeginInvoke(new Action(() => SetMessage(message)));
return;
}
button1.Text = message;
}
do you assume your form by View? if yes, you can call yourForm.Invoke( put delegate here ); , this will invoke the delegate in main thread. But why do you want to execute it in main thread? why can't you execute in thread of callback?
Related
In my WPF application I need to perform database operattions in the background to make the UI more responsive.
I'm making use of the BackgroungWorker class, but since it operates on different thread than that of UI, i can't pass the parameters to the database queries.These values comes from the UI controls.
Could anyone please help me with this problem or suggest some other way to do database operations,at the same time making UI responsive.
Thank You
Instead of using BackgroungWorker class you could work with Dispatcher.BeginInvoke method. In fact as specified by MSDN:
BeginInvoke is asynchronous; therefore, control returns immediately to the calling object after it is called.
In WPF, only the thread that created a DispatcherObject may access that object. For example, a background thread that is spun off from the main UI thread cannot update the contents of a Button that was created on the UI thread. In order for the background thread to access the Content property of the Button, the background thread must delegate the work to the Dispatcher associated with the UI thread. This is accomplished by using either Invoke or BeginInvoke. Invoke is synchronous and BeginInvoke is asynchronous. The operation is added to the event queue of the Dispatcher at the specified DispatcherPriority.
Here a good article that explains how to work with Dispatcher class.
I think the BackgroundWorker is the correct tool for the job. When you create a BackgroundWorker you specify an event handler for the DoWork event. The DoWorkEventArgs object has a property on it called Arguments which is the object passed in when you start the BackgroundWorker by calling RunWorkerAsync. You may need to create a helper class to handle the parameters you need to pass, but that should be quite easy. Something like
Helper Class:
public class WorkerArgs
{
public string Arg1 {get;set;}
public object Arg2 {get;set;}
public int Arg3 {get;set;}
}
Background Worker:
BackgroundWorker worker = new BackgroundWorker();
// Hook up DoWork event handler
worker.DoWork += (sender, e) => {
WorkerArgs args = e.Arguments as WorkerArgs;
// ... Do the rest of your background work
};
// Create arguments to pass to BackgroundWorker
WorkerArgs myWorkerArgs = new WorkerArgs {Arg1 = "Foo", Arg2 = new Object(), Arg3 = 123 };
// Start BackgroundWorker with arguments
worker.RunWorkerAsync(myWorkerArgs);
In your case, you would populate the helper class object with values from your UI controls.
I have a function like this:
public void UpdateList()
{
BindList = Model.GetList();
TreeView1.ItemsSource = BindList;
}
UpdateList() needs to be called (and the tree view list therefore reloaded) every time the user performs some action. It currently works, it's just very slow so I want to do it in another thread.
I am quite new to WPF... on WinForms programs I used to make delegates and check if InvokeRequired, etc. But I have found this does not work in WPF.
So if I want to call UpdateList() such that it runs in another thread, and the ItemsSource is updated from that other thread, how should I do it?
Thanks
Change Model.GetList() function to property of type ObservableCollection<> For example:
public ObservableCollection<DataItem> List { get; set; }
Call TreeView1.ItemsSource = Model.List only once. It gives you advantages of WPF binding.
Create a BackgroundWorker to load the data in DoWork handler. Load data to temporary collection and copy this collection to Model.List at RunWorkerCompleted handler.
If you want to update your tree while data is loading you may look at this approach: WPF update binding in a background thread
Read and learn MVVM pattern to understand the main idea of WPF developing
I'm developing a Windows Forms GUI in a design pattern which is a combination of MVP and MVVM.*
I'm binding the View to the View Model using code: the view subscribes to the VM's PropertyChanged event. If the presenter sets some property of the VM, the event is raised and the View executes its callback.
So every callback in the View needs to be wrapped in this.Invoke( { ... } ).
I wish there was a way to define a property whose setter will automatically be invoked in the UI thread. Some way to write an auto-delegating property or method.
I tagged this question with WPF as well, because I'm using C# 4.0, so if such a mechanism exists in WPF, I'll be happy to use it for Windows Forms.
*I'm using MVVM because the application will probably be converted to WPF at some stage.
I suddenly realized that the IoC Framework I'm using, Castle Windsor, can give me exactly that. I just attached an interceptor to all the methods of the form, and the interceptor does this:
if (invocation.InvocationTarget.InvokeRequired)
{
invocation.InvocationTarget.Invoke(invocation.Proceed);
}
else
{
invocation.Proceed();
}
Later I modified the above code by putting it in an extension method with the following signature:
public void InvokeIfRequired(this Control uiObject, Action action)
To define a property setter that always gets invoked on the UI thread, you could do something like this:
public int MyPropertyForTheUIThread
{
get
{
return this.myRealValue;
}
set
{
if (this.myRealValue != value)
{
this.myRealValue = value;
this.Invoke((Action)(()=>
{
// The stuff I want to do on the UI thread when this property changes.
});
}
}
}
Is there any way how to do
ICollectionView.Refresh()
or
CollectionViewSource.GetDefaultView(args.NewValue).Refresh();
in a separate thread?
I know I can use dispatcher, but this collection is binded to a ListView and it throws cross thread Exceptions.
The reason why I need a second thread is, that I have Control which displays a list of IMyItems. When filtering this Collection (by user text change input), I want to be able to display my animation that CollectionView is changing.
You can't!
All UI operations must happen on the user interface thread, and nearly every call inside of WPF's DispatcherObject (and all controls in that hierarchy) are regularly going to be calling CheckAccess().
You might want to consider using an ObservableCollection to help keep your data up-to-date, if you're doing processing in a background thread or BackgroundWorker.
How about using the Dispatcher to do work with background priority?
Dispatcher.Invoke(DispatcherPriority.Background,
() => { CollectionViewSource.GetDefaultView(args.NewValue).Refresh(); }
);
I hacked up a quick method to invoke actions on wpf dispatchable objects (all wpf controls inherit from DispatcherObject)
public static void InvokeWpf(DispatcherObject dispatchable, Action action, bool async)
{
// DispatcherOperationCallback is optimized for wpf invoke calls
DispatcherOperationCallback toDo = delegate{ action(); return null; };
if (!dispatchable.CheckAccess())
{
if (async)
dispatchable.Dispatcher.BeginInvoke(toDo, null);
else
dispatchable.Dispatcher.Invoke(toDo, null);
}
else
{
toDo(null);
}
}
Usage:
InvokeWpf(listView,
() => CollectionViewSource.GetDefaultView(listView).Refresh(),
false);
What is the use of a Dispatcher Object in WPF?
Almost every WPF element has thread affinity. This means that access to such an element should be made only from the thread that created the element.
In order to do so, every element that requires thread affinity is derived, eventually, from DispatcherObject class. This class provides a property named Dispatcher that returns the Dispatcher object associated with the WPF element.
The Dispatcher class is used to perform work on its attached thread. It has a queue of work items and it is in charge of executing the work items on the dispatcher thread.
You can find on the following link some more details on the subject:
https://www.codeproject.com/Articles/101423/WPF-Inside-Out-Dispatcher
A dispatcher is often used to invoke calls on another thread. An example would be if you have a background thread working, and you need to update the UI thread, you would need a dispatcher to do it.
In my experience we use Prism Event Aggregator. When the event happens it calls the Dispatcher.Invoke() to update the UI. This is because only the Dispatcher can update the objects in your UI from a non-UI thread.
public PaginatedObservableCollection<OrderItems> Orders { get; } = new PaginatedObservableCollection<OrderItems>(20);
_eventAggregator.GetEvent<OrderEvent>().Subscribe(orders =>
{
MainDispatcher.Invoke(() => AddOrders(orders));
});
private void AddOrders(List<OrderItems> orders)
{
foreach (OrderItems item in orders)
Orders.Add(item);
}