在线程之间移动DependencyObject

时间:2011-10-31 10:35:25

标签: c# wpf thread-safety

我在WPF应用程序的单独线程中执行冗长的操作(连接测试,远程数据库表的验证等)。在测试期间,我收集用户的信息,告知哪些测试已通过,哪些测试未通过。信息存储为我自己设计的List<T>个对象:

public class StatusItem : DependencyObject
{
    public string Text { get... set... }
    public Status Status { get... set... }
    public string Details { get... set... }
}

所有这些属性都是相应DependencyProperty的前端。当操作完成时(在单独的线程中),我将收集的信息status设置为Window上的私有字段。我得到了:

InvalidOperationException:
The calling thread cannot access this object because a different thread owns it.

我有没有办法将status(一个List<StatusItem>)从TestThread转移到我的主线程,而无需诉诸代理和Dispatcher调用?

PS:我可以Invoke,但我宁愿避免创建CopyStatusItemsDelegate代表。

3 个答案:

答案 0 :(得分:3)

我不认为有一个很好的解决方案。上述情况是我为什么不从DependencyObject派生Item-ViewModel而是实现INotifiyPropertyChanged的原因。

答案 1 :(得分:1)

关于msdn的DependencyObject:

  

只能从它所在的线程访问此对象   创建。试图从其他线程访问它会抛出一个   InvalidOperationException异常。 Invoke或BeginInvoke提供支持   编组工作到正确的线程。

如果您的案例中必须有DependencyObject,那么请使用Invoke。否则,我建议你使用INotifyPropertyChanged接口实现。

答案 2 :(得分:0)

如果您完全信任,可以使用以下黑客攻击:

public static class DispatcherExtenstions {
    public static void SetAccess(this DispatcherObject d) {
        if(d.CheckAccess()) return;
        Dispatcher dispatcher = d.Dispatcher;
        FieldInfo dispatcherThreadField = typeof(Dispatcher).GetField("_dispatcherThread", BindingFlags.Instance | BindingFlags.NonPublic);
        dispatcherThreadField.SetValue(dispatcher, Thread.CurrentThread);
}
}

样品:

public partial class MainWindow : Window {
    Button b;
    public MainWindow() {
        InitializeComponent();
        Thread t = new Thread(CreateButton);
        t.SetApartmentState(ApartmentState.STA);
        t.Start();
    }
    void CreateButton() {
        b = new Button() { Padding = new Thickness(20.0) };
        b.Content = new Button { Content = "Button" };
        Dispatcher.BeginInvoke((Action)ShowButton);
    }
    void ShowButton() {
        b.SetAccess();
        Content = b;
    }
}