在不同线程之间移动DependencyObject

3

我在WPF应用程序中的一个单独的线程中执行一项长时间操作(连接测试、验证远程DB表等)。在测试过程中,我会为用户收集关于哪些测试已经通过和哪些没有通过的信息。 这些信息被存储为由我自己设计的对象的 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个回答

3
我认为没有一个很好的解决方案。上述情况是我不从DependencyObject派生Item-ViewModels,而是实现INotifyPropertyChanged的原因。

@svick,从INotifyPropertyChanged发出的属性更改通知并不是线程不可知的。即使它们是从另一个线程引发的,它们也会委托给UI线程。 - WPF-it
@svick:正如我已经在你对invisible的评论中写过的那样,我认为你是错的。只要不是集合更改,绑定就会接受跨线程调用。 - HCL
@HCL,我一定是把它和集合更改混淆了。 - svick
经过一番思考,我意识到我不需要 DependencyObject。我已经改用 INPC 接口实现了。谢谢大家! - Minustar

1

关于来自 MSDN 的 DependencyObject:

此对象只能从创建它的线程访问。尝试从其他线程访问它将引发 InvalidOperationException 异常。Invoke 或 BeginInvoke 提供了将工作调度到正确线程的支持。

如果您必须在您的情况下使用 DependencyObject,则请使用 Invoke。否则,我建议您使用 INotifyPropertyChanged 接口实现。


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;
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接