WPF ICollectionView Refresh - wpf

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);

Related

Updating a TreeView ItemsSource in another thread

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

wpf BackgroundWorker - Regarding updating UI

I use a browse for files dialog to allow a user to select multiple images. If a lot of images are selected, as expected it takes a bit. Below is an example of what I do with the selected images. I loop through the filepaths to images and create an instance of a user control, the user control has an Image control and a few other controls. I create the instance of this control then add it to a existing stackPanel created in the associating window xaml file. The example just below works fine, but I'm trying to understand BackGroundWorker better, I get the basics of how to set it up, with it's events, and pass back a value that could update a progress bar, but because my loop that takes up time below adds the usercontrol instance to an existing stackPanel, It won't work, being in a different thread. Is BackGroundWorker something that would work for an example like this? If so, what's the best way to update the ui (my stackpanel) that is outside the thread. I'm fairly new to wpf and have never used the BackGroundWorker besides testing having it just update progress with a int value, so I hope this question makes sense, if I'm way off target just let me know. Thanks for any thoughts.
Example of how I'm doing it now, which does work fine.
protected void myMethod(string[] fileNames) {
MyUserControl uc;
foreach (String imagePath in fileNames) {
uc = new MyUserControl();
uc.setImage(imagePath);
stackPanel.Children.Add(uc);
progressBar.Value = ++counter;
progressBar.Refresh();
}
}
below this class i have this so I can have the progressBar refresh:
public static class extensionRefresh {
private static Action EmptyDelegate = delegate() { };
public static void Refresh(this UIElement uiElement) {
uiElement.Dispatcher.Invoke(DispatcherPriority.Background, EmptyDelegate);
}
}
Check out this article on
Building more responsive apps with the Dispatcher
Now that you have a sense of how the Dispatcher works, you might be surprised to know that you will not find use for it in most cases. In Windows Forms 2.0, Microsoft introduced a class for non-UI thread handling to simplify the development model for user interface developers. This class is called the BackgroundWorker
In WPF, this model is extended with a DispatcherSynchronizationContext class. By using BackgroundWorker, the Dispatcher is being employed automatically to invoke cross-thread method calls. The good news is that since you are probably already familiar with this common pattern, you can continue using BackgroundWorker in your new WPF projects
Basically the approach is
BackgroundWorker _backgroundWorker = new BackgroundWorker();
// Set up the Background Worker Events
_backgroundWorker.DoWork += _backgroundWorker_DoWork;
_backgroundWorker.RunWorkerCompleted += _backgroundWorker_RunWorkerCompleted;
// Run the Background Worker
_backgroundWorker.RunWorkerAsync(5000);
// Worker Method
void _backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
// Do something
}
// Completed Method
void _backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
// Doing UI stuff
if (e.Cancelled)
{
statusText.Text = "Cancelled";
}
else if (e.Error != null)
{
statusText.Text = "Exception Thrown";
}
else
{
statusText.Text = "Completed";
}
}
Using a BackgroundWorker alone won't solve your issue since elements created during the DoWork portion will still have originated from a non-UI thread. You must call Freeze on any objects you intend to use on another thread. However only certain UI objects will be freezable. You may have to load in the images as BitmapImages on the background thread, then create the rest of your user control on the UI thread. This may still accomplish your goals, since loading in the image is probably the most heavyweight operation.
Just remember to set BitmapImage.CacheOption to OnLoad, so it actually loads up the image when you create the object rather than waiting until it needs to be displayed.

Is there some shortcut for calling this.Invoke every time a callback needs to access the UI? Some automatic delegation to the UI thread?

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.
});
}
}
}

Access windows control from Backgroundworker DoWork

my issue is the following:
I have a windows form in which I've placed a LayoutPanel, when the forms Loads, multiple controls like: textboxes and labels are being added to the LayoutPanel.
Then on a button click, I need to process the data entered by the user on those dynamically created controls. For that purpouse I use a Backgroundworker which is supposed to take those controls and read their data.
My issue es that the Backgroundworker doesn't allows me to access the control from the DoWork Method, but I need to do it that way because I'll be reporting the progress of the operations.
Here are portions of my code to clarify the concept:
private void frmMyForm_Load(object sender, EventArgs e)
{
//I add multiple controls, this one is just for example
LayoutPanel1.add(TextBox1);
....
}
private void bgwBackground_DoWork(object sender, DoWorkEventArgs e)
{
foreach (Control controlOut in LayoutPanel1.Controls)
{
//do some stuff, this one is just for example
string myString = controlOut.Name; //-> Here is the error, cant access controls from different Thread.
}
}
Setting text is simple just using a delegate, but how about getting the entire parent control to manipulate the child controls (just for getting info, I don't want to set any data, just need to Get Name, Text, stuff like that).
Hope I made myself clear, thank you all.
You can only access Windows Forms controls from the GUI thread. If you want to manipulate them from another thread, you will need to use the Control.Invoke method to pass in a delegate to execute on the GUI thread. In your situation, you should be able to do this:
private void bgwBackground_DoWork(object sender, DoWorkEventArgs e)
{
foreach (Control controlOut in LayoutPanel1.Controls)
{
this.Invoke(new MethodInvoker(delegate {
// Execute the following code on the GUI thread.
string myString = controlOut.Name;
}));
}
}
I like to define an extension method that allows me to use the cleaner lambda syntax:
// Extension method.
internal static void Invoke(this Control control, Action action) {
control.Invoke(action);
}
// Code elsewhere.
this.Invoke(() => {
string myString = controlOut.Name;
});
As you are already aware, accessing control values from any thread other than the UI thread is a big no-no. I'd say one reasonable implementation is to use a .NET synchronization mechanism, such as a WaitHandle, to suspend your background thread while the UI thread updates a thread-safe data structure of your choice.
The idea is that your background thread notifies the UI thread (via the delegate mechanism you are already familiar with) that it needs information, then waits. When the UI is finished populating the shared variable with information, it resets the WaitHandle, and the background worker resumes.
Without writing out and testing all the code, let me give you a few resources:
WaitHandle.WaitOne documentation with example usage: http://msdn.microsoft.com/en-us/library/kzy257t0.aspx
My own favorite method of invoking an event on the UI thread: http://www.notesoncode.com/articles/2009/01/24/PowerfulExtensionMethodsPart1.aspx

What is the use of a Dispatcher Object in WPF?

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);
}

Resources