Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Maintaining a responsive WPF UI

Tags:

c#

mvvm

wpf

I've been trying to figure out how to do this for a couple of days now.

It's a fairly common problem so I'll explain the situation as generically as possible so maybe others can get a bit of use out of it.

I have a list view on my WPF (using MVVM) dialog, it's bound to an observable collection of items with, say, five properties which are displayed in seperate columns.

I call a function which iterates over all the items and changes one of their properties. This function takes a while to get through all the items so I want it to update each item as it goes.

What are the options to do this so the UI remains responsive, and which is the simplest to implement?

like image 556
Joshua Mee Avatar asked Feb 19 '26 21:02

Joshua Mee


2 Answers

If you are using C# 4.0, use

Task.Factory.StartNew(new Action(() =>
{
    .....
     //CALL YOUR UPDATE METHOD



 })).ContinueWith( { //something to execute after, if need}..)

and when set ModelView object from other thread, use

Application.Current.Dispatcher.Invoke(new Action(() =>
{
    //set ModelView object properties here
}));
like image 81
Tigran Avatar answered Feb 21 '26 10:02

Tigran


I would use an ObservableCollection Extender that allows you to update the collection in another thread. This is what I use in my applications when dealing with collections:

public class ObservableCollectionExtender<T> : ObservableCollection<T>
{
    /// <summary>
    /// Source: New Things I Learned
    /// Title: Have worker thread update ObservableCollection that is bound to a ListCollectionView
    /// http://geekswithblogs.net/NewThingsILearned/archive/2008/01/16/have-worker-thread-update-observablecollection-that-is-bound-to-a.aspx
    /// Note: Improved for clarity and the following of proper coding standards.
    /// </summary>
    /// <param name="e"></param>
    protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
    {
        // Use BlockReentrancy
        using (BlockReentrancy())
        {
            var eventHandler = CollectionChanged;

            // Only proceed if handler exists.
            if (eventHandler != null)
            {
                Delegate[] delegates = eventHandler.GetInvocationList();

                // Walk thru invocation list
                foreach (NotifyCollectionChangedEventHandler handler in delegates)
                {
                    var currentDispatcher = handler.Target as DispatcherObject;

                    // If the subscriber is a DispatcherObject and different thread
                    if ((currentDispatcher != null) &&
                        (currentDispatcher.CheckAccess() == false))
                    {
                        // Invoke handler in the target dispatcher's thread
                        currentDispatcher.Dispatcher.Invoke(
                            DispatcherPriority.DataBind, handler, this, e);
                    }

                    else
                    {
                        handler(this, e);
                    }
                }
            }
        }
    }

    /// <summary>
    /// Overridden NotifyCollectionChangedEventHandler event.
    /// </summary>
    public override event NotifyCollectionChangedEventHandler CollectionChanged;
}
like image 30
Xcalibur37 Avatar answered Feb 21 '26 11:02

Xcalibur37



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!