使用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(); }); } } }