У меня есть DLL, которая запускает рабочий поток и отправляет события обратно в приложение - отлично работало на формах Windows, переключилось на WPF и все перестало работать. Я 4 часа разбиваю голову о кирпичную стену, пытаясь заставить это работать. Но решение, с которым я в итоге справился, благодаря Microsoft Thread UI Thread Safe, поддерживающему функцию EnableCollectionSynchronization, дает действительно чистую реализацию для решения этой проблемы.
Эта коллекция расширяет ObservableCollection и реализует EnableCollectionSynchronization, благодаря чему эти объекты можно использовать между WPF и фоновыми работниками.
Редактировать : Документы Microsoft говорят следующее, поэтому я предполагаю, что совместное использование контекста объекта не имеет значения.
Параметр context - это произвольный объект, который вы можете использовать для информации, известной при включении синхронизации коллекции. Контекст может быть null .
ThreadSafeCollection.cs
using System.Collections.ObjectModel;
using System.Windows.Data;
namespace NSYourApplication
{
/// <summary>
/// This ObservableCollection is thread safe
/// You can update it from any thread and the changes will be safely
/// marshalled to the UI Thread WPF bindings
/// Thanks Microsoft!
/// </summary>
/// <typeparam name="T">Whatever type of collection you want!</typeparam>
public class ThreadSafeCollection<T> : ObservableCollection<T>
{
private static object __threadsafelock = new object();
public ThreadSafeCollection()
{
BindingOperations.EnableCollectionSynchronization(this, __threadsafelock);
}
}
}
Пример WindowViewModel
WindowViewModel.cs
namespace NSYourApplication
{
/// <summary>
/// Example View
/// BaseModelView implements "PropertyChanged" to update WPF automagically
/// </summary>
class TestViewModel : BaseModelView
{
public ThreadSafeCollection<string> StringCollection { get; set; }
/// <summary>
/// background thread implemented elsewhere...
/// but it calls this method eventually ;)
/// Depending on the complexity you might want to implement
/// [MethodImpl(MethodImplOptions.Synchronized)]
/// to Synchronize multiple threads to prevent chase-conditions,deadlocks etc
/// </summary>
public void NonUIThreadMethod()
{
// No dispatchers or invokes required here!
StringCollection.Add("Some Text from a background worker");
}
/// <summary>
/// Somewhere in the UIThread code it'll call this method
/// </summary>
public void UIThreadMethod()
{
StringCollection.Add("This text come from UI Thread");
}
/// <summary>
/// Constructor, creates a thread-safe collection
/// </summary>
public TestViewModel()
{
StringCollection = new ThreadSafeCollection<string>();
}
}
}
Использование в списке в окне xaml / control
MainWindow.xaml
<ListBox x:Name="wpfStringCollection" ItemsSource="{Binding StringCollection,Mode=OneWay}">
</ListBox>