Using BindingOperations.EnableCollectionSynchronization
Solution 1
All the examples I've seen on Stack Overflow for this get it wrong. You must lock the collection when modifying it from another thread.
On dispatcher (UI) thread:
_itemsLock = new object();
Items = new ObservableCollection<Item>();
BindingOperations.EnableCollectionSynchronization(Items, _itemsLock);
Then from another thread:
lock (_itemsLock)
{
// Once locked, you can manipulate the collection safely from another thread
Items.Add(new Item());
Items.RemoveAt(0);
}
More information in this article: http://10rem.net/blog/2012/01/20/wpf-45-cross-thread-collection-synchronization-redux
Solution 2
I am not sure if this will help but still you can give it a try.
Add a Property
in Debugger
which will hold the Collection
from BL
like
private ObservableCollection<string> _data = new ObservableCollection<string>();
private object _lock = new object();
public ObservableCollection<string> Data { get {return _data;} }
In the constructor just add the below line
BindingOperations.EnableCollectionSynchronization(_data, _lock);
this will above line will take care of thread safety.
Below is the example
ViewModel (Debugger
)
internal class ViewModelClass : INotifyPropertyChanged
{
private object _lock = new object ();
private ObservableCollection<string> _data;
public ObservableCollection<string> 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;
}
Model(BL
)
internal class ModelClass
{
private ObservableCollection<string> _data;
public ObservableCollection<string> Data
{
get { return _data; }
private set { _data = value; }
}
public ModelClass ()
{
_data = new ObservableCollection<string> { "Test1", "Test2", "Test3" };
}
}
MainWindow.xaml.cs
public partial class MainWindow : Window
{
public MainWindow ()
{
InitializeComponent ();
this.DataContext = new ViewModelClass ();
}
}
MainWindow.xaml
<Window x:Class="CollectionSynchronizationTest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow"
Height="350"
Width="525">
<StackPanel>
<ComboBox IsEditable="True"
ItemsSource="{Binding Data}"
Text="{Binding EnteredText, Mode=TwoWay, UpdateSourceTrigger=LostFocus}" />
<Button Content="Test" />
</StackPanel>
When the window loads just enter "SomeValue" in the ComboBox
and then after pressing the Tab
key you should find the new value in the ComboBox
dropdown
Related videos on Youtube
![Dilshod](https://i.stack.imgur.com/DvyHk.jpg?s=256&g=1)
Dilshod
Updated on July 09, 2022Comments
-
Dilshod almost 2 years
I have two WPF applications "UI", "Debugger" and one ClassLibrary "BL". UI references to Debugger and BL. Debugger references to BL. I have collection in BL called MyCollection. UI app starts the Debugger app and Debugger binds to a collection MyCollection in BL. When I try changing the MyCollection collection from UI app I am getting 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.
I was googling around and found this: BindingOperations.EnableCollectionSynchronization I can't figure out how to use it. I don't want to reference to any UI dlls from my BL project. Can anybody assist me on that?
Thanks for the help!
-
Dilshod over 10 yearsWhat is the point of having NotifyPropertyChanged for ObservableCollection<T>?
-
Sandesh over 10 yearsThe
INotifyPropertyChanged
interface is used to notify the UI for any data change in the ViewModel. Otherwise theUI
will never get new values. -
Dilshod over 10 yearsObservableCollection<T> does that for you. So you don't need to use it for ObservableCollections.
-
claudekennilol over 8 years"BindingOperations.EnableCollectionSynchronization(_data, _lock);" doesn't take care of thread safety. You still have to lock the _lock object.
-
Sandesh over 8 yearsThe _lock is used internally to synchronize the access to the IEnumerable object. There would be no point in using the BindingOperation if you had to use an explicit lock statement again
-
Drew Noakes over 7 yearsWhy do you have to pass a lock in? That suggests you are supposed to also lock with it from other threads too, no? Otherwise the collection could just allocate the lock internally. There's no clear indication of this in the documentation.
-
Drew Noakes over 7 yearsThis doesn't use the technique asked about in the question (
BindingOperations.EnableCollectionSynchronization
). -
Drew Noakes over 7 yearsYou do have to lock on the lock object when modifying the collection from another thread (you just don't have to dispatch to the UI thread to do it). See this article for more info: 10rem.net/blog/2012/01/20/…
-
ToolmakerSteve about 4 yearsI don't see the line
BindingOperations.EnableCollectionSynchronization(_data, _lock);
anywhere in the sample code. (Yet that was the entire point of this example.) it could be added in constructorpublic ViewModelClass ()
, afterData = _model.Data;
. OR it could be put into Data's setter:if (value != null) BindingOperations.EnableCollectionSynchronization(value, _lock);
-
ToolmakerSteve about 4 years@claudekennilol is correct: your code must do
lock(_lock){ ... }
around any accesses you do to the ObservableCollection. All thatEnableCollectionSynchronization
does is make WPF lock its code, using the same lock as you. This sample code is (dangerously) incomplete. -
ed22 about 3 yearsI assume this will queue some collection update events until the lock is freed and they can be processed by the GUI, correct?