【问题标题】:The calling thread cannot access this object because a different thread owns it when using animation in wpf window调用线程无法访问此对象,因为在 wpf 窗口中使用动画时,另一个线程拥有它
【发布时间】:2012-11-20 11:37:23
【问题描述】:

根据我们的要求,我们必须在新的 UI 线程中打开一个 WPF 窗口。

我们正在使用以下代码在主 UI 线程的新 UI 线程中打开窗口:

Thread winthread = new Thread(new ThreadStart(() =>
{
    SynchronizationContext.SetSynchronizationContext(
        new DispatcherSynchronizationContext(
            Dispatcher.CurrentDispatcher));
    Window windowObj = new Window();
    Grid gridObj = new Grid();
    MyUserControl ctrl = new MyUserControl();
    gridObj.Children.Add(ctrl);
    windowObj.Content = gridObj;

    windowObj.Show();
    System.Windows.Threading.Dispatcher.Run();
}));

winthread.IsBackground = true;
winthread.SetApartmentState(ApartmentState.STA);
winthread.Start();

执行上述代码时,窗口将显示MyUserControl 作为内容。 我正在做一些动画,比如在鼠标双击事件上翻转我的用户控件。

当我双击它时,应用程序开始抛出以下异常:

调用线程无法访问此对象,因为另一个线程拥有它。

在线System.Windows.Threading.Dispatcher.Run().

谁能提出这个问题的解决方案?

【问题讨论】:

  • 抱歉学究了,但这是因为线程无法访问该对象,因为不同的线程拥有它。您不完全理解哪一点,也许我们可以提供帮助?
  • @ Kieren Johnstone :- 更清楚地说,我的动画应该在逻辑上完美运行,因为它在创建窗口的同一线程上运行,它不应该抛出任何异常。
  • 您的代码看起来不错 - 这对我来说运行良好(仅用 Button 替换 MyUserControl)。你能显示MyUserControl 的代码吗?你能展示你是如何调用这个代码的吗?从现有的 WPF 应用程序?控制台应用程序?
  • @J... 抱歉,我无法分享 MyUserControl 的完整代码,因为它非常庞大并且分布在多个类中,但我可以简要介绍一下它的功能。它包含一个标签,该标签通过实时数据不断更新。当我们翻转用户控件时,我正在创建与该特定用户控件相对应的图形,然后它将开始在图形上绘制实时数据

标签: c# wpf multithreading


【解决方案1】:

您上面的代码很好。无论问题是什么,它都在 MyUserControl 内部——这些类中必须有共享元素或对主线程拥有的对象的引用。您必须确保 MyUserControl 中的任何内容都没有在主线程上创建或归主线程所有,包括作为参数传递的对象等。

或者,您可能正在尝试使用主线程与MyUserControl(或内部组件)进行交互。如果您想从外部线程(即:主线程等)对 ctrl 执行任何操作,您必须保留对 ctrl 的引用并使用调用 - 如下所示:

public partial class MainWindow : Window
{
    UserControl1 ctrl;

    public MainWindow()
    {
        InitializeComponent();
    }

    private void button1_Click(object sender, RoutedEventArgs e)
    {
        Thread winthread = new Thread(new ThreadStart(() =>
        {
            SynchronizationContext.SetSynchronizationContext(
                new DispatcherSynchronizationContext(
                    Dispatcher.CurrentDispatcher));
            Window windowObj = new Window();
            Grid gridObj = new Grid();
            ctrl = new UserControl1();
            gridObj.Children.Add(ctrl);
            windowObj.Content = gridObj;

            windowObj.Show();
            System.Windows.Threading.Dispatcher.Run();
        }));

        winthread.IsBackground = true;
        winthread.SetApartmentState(ApartmentState.STA);
        winthread.Start();
    }

    private void button2_Click(object sender, RoutedEventArgs e)
    {
        ctrl.Dispatcher.Invoke(new Action(() => ctrl.AddStuff()));
    }
}

在这里,我制作了 UserControl1 一个带有列表框的简单窗口:

public partial class UserControl1 : UserControl
{
    private int i;

    public UserControl1()
    {
        InitializeComponent();
    }

    public void AddStuff()
    {
        listBox1.Items.Add("This is line : " + i.ToString());
        i += 1;
    }
}

在上述情况下,您必须确保主线程使用调用 - 特别是它查看 ctrl 的调度程序来处理调用。而不是使用它自己的调度程序(这会导致跨线程错误)主线程编组调用ctrl的调度程序。

如果您至少可以在 MyUserControl 中显示您遇到异常的代码行,那将会有所帮助。

【讨论】:

  • 感谢@J..您的宝贵建议,我将确保验证我的代码中提到的上述内容,如果我能成功,我会通知您:)
【解决方案2】:

听起来像是调用问题:

相当容易解决,因为您尝试在不同的线程中更改网格/窗口。

更改线程以调用更改

http://social.msdn.microsoft.com/forums/en-US/wpf/thread/360540eb-d756-4434-86f9-a3449f05eb55

【讨论】:

  • 感谢 Rikoshay 的宝贵建议,我正在创建网格的同一线程上制作动画。所以我认为在这种情况下不需要调用。如果我的方法有误,请纠正我
  • 你得到的错误是调用问题,你试过调用吗?
  • Rikshoy.. 我尝试在我的动画代码 Dispatcher.Invoke(new Action(() => { _frontRotation.BeginAnimation(AxisAngleRotation3D.AngleProperty, frontAnimation); _backRotation.BeginAnimation(AxisAngleRotation3D.AngleProperty, backAnimation) 上调用); camera.BeginAnimation(PerspectiveCamera.PositionProperty, cameraZoomAnim); this.IsRotating = true; this.IsRotated = true; }));但没有成功:(
猜你喜欢
  • 1970-01-01
  • 2011-02-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-02-13
相关资源
最近更新 更多