Normally I check if I have access to the ObservableCollection
and if not, I call a Dispatcher
. Here (on Stackoverflow
) are also some other solutions, but I don't know what is the best and cleanest way. I think my solution is obsolete and should not be used anymore.
In my example is the ItemsCollection
bound to the UI
. The _UpdateTheCollectionFromAnotherThread()
would being called (from another thread
or would open another thread
) and save the data temporary to items
. After that I would check the access and call a dispatcher
if needed.
Is this the way I have to go or are there some better and cleaner solutions?
public class FooClass
{
// ##############################################################################################################################
// Properties
// ##############################################################################################################################
/// <summary>
/// This Items are bound to my UI.
/// </summary>
public ObservableCollection<string> ItemsCollection { get; } = new ObservableCollection<string>();
// ##############################################################################################################################
// Singleton pattern
// ##############################################################################################################################
/// <summary>
/// The instance of <see cref="FooClass"/>.
/// </summary>
internal static FooClass Instance => _Instance ?? (_Instance = new FooClass());
private static FooClass _Instance;
// ##############################################################################################################################
// Konstruktor
// ##############################################################################################################################
private FooClass()
{
}
// ##############################################################################################################################
// Method
// ##############################################################################################################################
private void _UpdateTheCollectionFromAnotherThread()
{
List<string> items = new List<string>();
//Here would be some logic to create and fill the items list....
//and now apply them to the public list
if (System.Windows.Application.Current.Dispatcher.CheckAccess())
{
ItemsCollection.Clear();
foreach (string item in items)
{
ItemsCollection.Add(item);
}
}
else
{
System.Windows.Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Normal, new Action(() =>
{
ItemsCollection.Clear();
foreach (string item in items)
{
ItemsCollection.Add(item);
}
}));
}
}
}
If you are on .NET Framework 4.5 or later you can enable the collection to be accessed across multiple threads by calling the BindingOperations.EnableCollectionSynchronization
method. Note that this method must be called on the UI thread:
public class FooClass
{
private readonly object _lock = new object();
public ObservableCollection<string> ItemsCollection { get; } = new ObservableCollection<string>();
internal static FooClass Instance => _Instance ?? (_Instance = new FooClass());
private static FooClass _Instance;
private FooClass()
{
BindingOperations.EnableCollectionSynchronization(ItemsCollection, _lock);
}
private void _UpdateTheCollectionFromAnotherThread()
{
List<string> items = new List<string>();
ItemsCollection.Clear();
foreach (string item in items)
{
ItemsCollection.Add(item);
}
}
}
If the FooClass
may be created on a background thread, you might still improve your code a bit by not repeating yourself:
public class FooClass
{
public ObservableCollection<string> ItemsCollection { get; } = new ObservableCollection<string>();
internal static FooClass Instance => _Instance ?? (_Instance = new FooClass());
private static FooClass _Instance;
private FooClass() { }
private void _UpdateTheCollectionFromAnotherThread()
{
List<string> items = new List<string>();
if (System.Windows.Application.Current.Dispatcher.CheckAccess())
ClearCollection(items);
else
System.Windows.Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Normal, new Action(() => ClearCollection(items)));
}
private void ClearCollection(List<string> items)
{
ItemsCollection.Clear();
foreach (string item in items)
{
ItemsCollection.Add(item);
}
}
}