在线程之间移动 DependencyObject

发布于 2024-12-13 01:16:05 字数 757 浏览 1 评论 0原文

我在 WPF 应用程序的单独线程中执行冗长的操作(连接测试、远程数据库表验证等)。在测试过程中,我为用户收集有关哪些测试通过、哪些测试未通过的信息。这些信息存储为我自己设计的对象的 List

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

所有这些属性都是其相应 DependencyProperty 的前面。操作完成后(在单独的线程中),我将收集的信息“状态”设置为“窗口”上的私有字段。我得到一个:

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

有没有办法让我将 statusList)从 TestThread 传输到我的主线程,而不必求助于委托和 调度程序调用?

PS:我可以执行 Invoke,但我宁愿避免创建 CopyStatusItemsDelegate 委托。

I perform a lengthy operation (connection test, validation of remote DB tables, etc.) in a separate thread in a WPF app. During the testing, I collect information for the user about which tests were passed and which weren't. The information is stored as a List<T> of objects of my own design:

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

All these properties are a front for their corresponding DependencyProperty. When the operation is completed (in the separate thread), I set the collected info, status, to a private field on my Window. I get a:

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

Is there a way for me to transfer status (a List<StatusItem>) from TestThread to my main thread without having to resort to delegates and Dispatcher invokes?

PS: I could do Invoke, but I'd rather avoid having to create a CopyStatusItemsDelegate delegate.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

小镇女孩 2024-12-20 01:16:05

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

I don't think there is a nice solution. The above situation is the reason, why I don't derive Item-ViewModels from DependencyObject but implement INotifiyPropertyChanged.

口干舌燥 2024-12-20 01:16:05

关于 DependencyObject 来自 msdn:

该对象只能从它所在的线程访问
创建的。尝试从其他线程访问它会抛出
无效操作异常。 Invoke 或 BeginInvoke 提供支持
将工作编组到正确的线程。

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

About DependencyObject from msdn:

This object can be accessed only from the thread on which it was
created. Attempts to access it from other threads will throw an
InvalidOperationException. Invoke or BeginInvoke provide support for
marshalling work to the correct thread.

If you must have DependencyObject in your case, so use Invoke. Otherwise, I suggest you to use INotifyPropertyChanged interface implementations.

自控 2024-12-20 01:16:05

如果您完全信任,您可以使用以下技巧:

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

You can use the following hack if you have full trust:

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

Sample:

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;
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文