You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

WPF线程报错:调用线程无法访问其他线程拥有的对象

解决WPF跨线程访问UI控件的错误

首先,咱们来搞清楚你遇到的这个错误的根源:WPF的UI元素有严格的线程亲和性——每个控件都只能由创建它的线程(必须是STA线程)来访问和操作。你现在的问题出在:LoadCurrentBetween这个UserControl是在Window2所在的新线程里创建的,它的Dispatcher属于那个新线程,但你试图把它赋值给MainWindow(属于主线程)的Content属性,这就导致了跨线程访问的错误,也就是你看到的:

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

修复方案一:让UI元素始终在主线程创建

核心思路是:所有需要显示在MainWindow里的UserControl,都必须在MainWindow的线程(也就是应用主线程)中创建,避免跨线程操作UI控件。

步骤1:修改Switcher类,添加带数据的切换方法

我们把创建UserControl和赋值的逻辑都放到主线程执行:

public static class Switcher
{
    public static MainWindow pageSwitcher;

    public static void Switch(UserControl newPage)
    {
        pageSwitcher.Navigate(newPage);
    }

    // 新增:接收数据,在主线程创建控件并切换
    public static void SwitchWithProductData(dynamic productData)
    {
        // 确保在MainWindow的线程执行
        pageSwitcher.Dispatcher.Invoke(() =>
        {
            LoadCurrentBetween loadCurrentbtw = new LoadCurrentBetween();
            // 这里注意:如果LoadCurrentdetails是loadCurrentbtw的实例属性,要改成实例访问
            // 比如:loadCurrentbtw.LoadCurrentdetails.Part = productData.Part;
            LoadCurrentdetails.Part = productData.Part;
            Switch(loadCurrentbtw);
        });
    }
}

步骤2:修改Window2的按钮点击事件

不要在Window2的线程创建UserControl,直接调用Switcher的新方法传递数据:

private void EnterProduct(object sender, RoutedEventArgs e)
{
    var data = ProductDetailsData;
    // 直接把数据传给主线程处理,不在当前线程创建UI控件
    Switcher.SwitchWithProductData(data);
}

步骤3:简化MainWindow的Navigate方法

现在UserControl是在主线程创建的,不需要额外的Dispatcher调用:

public void Navigate(UserControl nextPage)
{
    this.Content = nextPage;
}

修复方案二:避免用额外线程打开Window2(更推荐)

其实在WPF中,如果Window2不需要在后台独立运行,完全没必要用新线程打开它,直接用ShowDialog()模态打开更简单,还能避免所有线程问题:

修改打开Window2的代码:

private void Button_Click_2(object sender, RoutedEventArgs e)
{
    Scanner w = new Scanner();
    // 模态打开窗口,等待窗口关闭后获取数据
    if (w.ShowDialog() == true)
    {
        var data = w.ProductDetailsData;
        LoadCurrentBetween loadCurrentbtw = new LoadCurrentBetween();
        LoadCurrentdetails.Part = data.Part;
        Switcher.Switch(loadCurrentbtw);
    }
}

然后在Window2的EnterProduct方法中,设置DialogResult并关闭窗口:

private void EnterProduct(object sender, RoutedEventArgs e)
{
    // 可以在这里把数据赋值给Window2的公共属性
    this.ProductDetailsData = ProductDetailsData;
    this.DialogResult = true;
    this.Close();
}

这种方式完全不需要处理多线程,代码更简洁,也更符合WPF的设计规范。

内容的提问来源于stack exchange,提问作者RackM

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 09:59:58