使用BindingOperations.EnableCollectionSynchronization

我有两个WPF应用程序“UI”,“调试器”和一个ClassLibrary“BL”。 UI对Debugger和BL的引用。 调试器引用BL。 我在BL中收集了名为MyCollection的集合。 UI应用程序启动调试器应用程序,调试器绑定到BL中的集合MyCollection。 当我尝试从UI应用程序更改MyCollection集合时,我遇到exception。

A first chance exception of type 'System.NotSupportedException' occurred in PresentationFramework.dll Additional information: This type of CollectionView does not support changes to its SourceCollection from a thread different from the Dispatcher thread. 

我在google搜索并发现: BindingOperations.EnableCollectionSynchronization我无法弄清楚如何使用它。 我不想引用我的BL项目中的任何UI dll。 任何人都能协助我吗?

谢谢您的帮助!

我在Stack Overflow上看到的所有示例都是错误的。 从其他线程修改集合时, 必须锁定集合。

在调度程序(UI)线程上:

 _itemsLock = new object(); Items = new ObservableCollection(); BindingOperations.EnableCollectionSynchronization(Items, _itemsLock); 

然后从另一个线程:

 lock (_itemsLock) { // Once locked, you can manipulate the collection safely from another thread Items.Add(new Item()); Items.RemoveAt(0); } 

本文中的更多信息: http :/ 10/ 10rem.net/blog/2012/01/20/wpf-45-cross-thread-collection-synchronization-redux

我不确定这是否会有所帮助,但你仍然可以尝试一下。

Debugger添加一个Property ,它将从BL保存Collection

 private ObservableCollection _data = new ObservableCollection(); private object _lock = new object(); public ObservableCollection Data { get {return _data;} } 

在构造函数中只需添加以下行

 BindingOperations.EnableCollectionSynchronization(_data, _lock); 

这将上面的线将照顾线程安全。

以下是示例

ViewModel( Debugger

 internal class ViewModelClass : INotifyPropertyChanged { private object _lock = new object (); private ObservableCollection _data; public ObservableCollection Data { get { return _data; } private set { _data = value; RaisePropertyChanged ("Data"); } } private string _enteredText; public string EnteredText { get { return _enteredText; } set { _enteredText = value; _data.Add (value); RaisePropertyChanged ("EnteredText"); } } private void RaisePropertyChanged (string name) { var pc = PropertyChanged; if (pc != null) pc (this, new PropertyChangedEventArgs (name)); } public ViewModelClass () { var _model = new ModelClass (); Data = _model.Data; _data.CollectionChanged += (s, e) => RaisePropertyChanged ("Data"); } public event PropertyChangedEventHandler PropertyChanged; } 

型号( BL

 internal class ModelClass { private ObservableCollection _data; public ObservableCollection Data { get { return _data; } private set { _data = value; } } public ModelClass () { _data = new ObservableCollection { "Test1", "Test2", "Test3" }; } } 

MainWindow.xaml.cs

 public partial class MainWindow : Window { public MainWindow () { InitializeComponent (); this.DataContext = new ViewModelClass (); } } 

MainWindow.xaml

      

当窗口加载时,只需在ComboBox输入“SomeValue”,然后在按Tab键后,您应该在ComboBox下拉列表中找到新值

在这篇博客中,您可以找到一个简单的教程,如何使用BindingOperations ……这很容易。

当我遇到同样的问题时,我也无法弄清楚如何使用它。

我以自己的集合类型结束,我存储调度程序并在必要时使用它。 请注意,我的命名非常差,这个集合不是线程安全的,远非如此。

 public class ThreadableObservableCollection : ObservableCollection { private readonly Dispatcher _dispatcher; public ThreadableObservableCollection() { _dispatcher = Dispatcher.CurrentDispatcher; } public void ThreadsafeRemove(T item, Action callback) { if (_dispatcher.CheckAccess()) { Remove(item); callback(); } else { _dispatcher.Invoke(() => { Remove(item); callback(); }); } } public void ThreadsafeInsert(int pos, T item, Action callback) { if (_dispatcher.CheckAccess()) { Insert(pos, item); callback(); } else { _dispatcher.Invoke(() => { Insert(pos, item); callback(); }); } } }