Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

WPF ObservableList Dispatcher thread

I'm converting a project from Windows Forms to WPF format. Currently, I've bounded all the data to elements. I now raise a problem in ObservableCollection, saying:

This type of CollectionView does not support changes to its SourceCollection from a thread different from the Dispatcher thread.

How can I make my code threadsafe? Or how do I guide the changes to the Dispatcher thread? I've seen a few posts about it but I'm confused on how to apply it on my own project. Maybe someone can shed some light on this for me?

This is my code of ObservableList.cs:

public class ObservableList<T> : ObservableCollection<T>
{
    #region Private members

    bool isInAddRange = false;

    #endregion Private members

    #region Public methods

    /// <summary>
    /// Creates a new empty ObservableList of the provided type. 
    /// </summary>
    public ObservableList()
    {

    }

    /// <summary>
    /// Handles the event when a collection has changed.
    /// </summary>
    /// <param name="e"></param>
    protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
    {
        // intercept this when it gets called inside the AddRange method.
        if (!isInAddRange)
            base.OnCollectionChanged(e);
    }

    /// <summary>
    /// Adds a collection of items to the ObservableList.
    /// </summary>
    /// <param name="items"></param>
    public void AddRange(IEnumerable<T> items)
    {
        isInAddRange = true;
        foreach (T item in items)
        {
            Add(item);
        }

        isInAddRange = false;

        var e = new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add,items.ToList());
        base.OnCollectionChanged(e);

    }

    #endregion Public methods
}

}

EDIT: After the answer given by ywm I changed my AddRange class to:

public void AddRange(IEnumerable<T> items)
{
    isInAddRange = true;
    foreach (T item in items)
    {
        if (item != null)
        {
            Dispatcher.CurrentDispatcher.Invoke((Action)(() =>
                {
                    Add(item);
                }));
        }
    }

    isInAddRange = false;

    var e = new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add,items.ToList());
    base.OnCollectionChanged(e);

}

Now, all my ObservableList's are null.

like image 502
Joetjah Avatar asked Dec 10 '25 00:12

Joetjah


1 Answers

When you add items to an ObservableCollection you need to invoke the UI dispatcher thread to do so.

This is done like so:

  Dispatcher.CurrentDispatcher.Invoke(() =>
  {
        foreach (var myModel in itemsToAdd)
        {
                    Images.Add(mymodel);                   
        } 
  });

Then in the class using it,

    public ObservableList<String> Strings { get; set; }

    public MyViewModel()
    {
        this.Strings = new ObservableList<string>();

        this.Strings.AddRange(new[] { "1", "2", "3", "4" });
    }
like image 105
ywm Avatar answered Dec 11 '25 13:12

ywm



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!