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
相关产品推荐
相关产品推荐

