我有一个运行工作线程并将事件发送回应用程序的 DLL - 在 Windows 窗体上完美运行,切换到 WPF 并且一切都停止工作。我已经把头撞在砖墙上了 4 个小时,试图让它发挥作用。但由于微软的 UI 线程安全编组 EnableCollectionSynchronization,我最终得到的解决方案提供了一个非常干净的实现来解决这个问题。
此集合扩展了 ObservableCollection 并实现了 EnableCollectionSynchronization,使这些对象可在 WPF 和后台工作人员之间使用。
编辑:Microsoft's docs 说如下,所以我假设对象上下文共享无关紧要。
上下文参数是一个任意对象,您可以在启用集合同步时使用它来获取已知信息。上下文可以是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 窗口/控件的列表框中使用
MainWindow.xaml
<ListBox x:Name="wpfStringCollection" ItemsSource="{Binding StringCollection,Mode=OneWay}">
</ListBox>