WPF: Accessing bound ObservableCollection fails al

2019-05-21 12:35发布

问题:

I have the following:

public ICollectionView Children
{
 get
 {
  // Determining if the object has children may be time-consuming because of network timeouts.
  // Put that in a separate thread and only show the expander (+ sign) if and when children were found
  ThreadPool.QueueUserWorkItem(delegate 
  {
   if (_objectBase.HasChildren)
   {
    // We cannot add to a bound variable in a non-UI thread. Queue the add operation up in the UI dispatcher.
    // Only add if count is (still!) zero.
    Application.Current.Dispatcher.BeginInvoke(new Action(() =>
    {
     if (_children.Count == 0)
     {
      _children.Add(DummyChild);
      HasDummyChild = true;
     }
    }),
    System.Windows.Threading.DispatcherPriority.DataBind);
   }
  });

  return _childrenView; 
 }
}

It works great: HasChildren is run in a background thread which uses the dispatcher to insert its result into the variable used for the binding to the UI.

Note: _childrenView is set to this:

_childrenView = (ListCollectionView) CollectionViewSource.GetDefaultView(_children);

Problem:

If I call the Children property from another ThreadPool thread, I get a NotSupportedException in the line

_children.Add(DummyChild);

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

Why? I have verified that that code is executed from the Dispatcher thread.

回答1:

We've run into this problem before ourselves. The issue is twofold:

1- Make sure that any changes to the SourceCollection are on the main thread (you've done that).

2- Make sure that the creation of the CollectionView was also on the main thread (if it were created on a different thread, say in response to an event handler, this will not usually be the case). The CollectionView expects modifications to be on "its" thread, AND that "its" thread is the "UI" thread.