从不同的线程访问GUI线程会抛出异常

时间:2013-10-23 22:43:22

标签: c# wpf multithreading dispatcher

我正在尝试在特定蓝牙消息到达时在我的应用程序中显示一个菜单元素。通过计时器方法收集和解释消息,如果到达正确的消息,则应该使元素可见。我一直得到一个异常,告诉我该对象是另一个线程拥有的,无法访问。

// Shows a TangibleMenu element
private void Show(TangibleMenu TangibleMenuElement)
{
    if (TangibleMenuElement.Shape.CheckAccess())
    {
        Debug.WriteLine("normal show");
        TangibleMenuElement.Shape.Opacity = 1;
        TangibleMenuElement.Shape.Visibility = System.Windows.Visibility.Visible;
        this.ParentContainer.Activate(TangibleMenuElement.Shape);
    }
    else
    {
        Dispatcher.CurrentDispatcher.Invoke(new Action(() =>
        {
            Debug.WriteLine("dispatcher show");
            TangibleMenuElement.Shape.Opacity = 1; // EXCEPTION HERE
            TangibleMenuElement.Shape.Visibility = System.Windows.Visibility.Visible;
            this.ParentContainer.Activate(TangibleMenuElement.Shape);
        }));
    }
}

我认为这个确切的问题可以通过使用Dispatcher来解决,但在这种情况下,它似乎不起作用。 TangibleMenuElement.Shape是Microsoft Surface SDK中的ScatterViewItem。有没有人有任何建议?

3 个答案:

答案 0 :(得分:0)

TangibleMenuElement需要在UI线程上创建,而不仅仅是添加到UI线程上的容器中。这意味着您需要在UI线程上完全构造FrameworkElement

答案 1 :(得分:0)

试试这个

// Shows a TangibleMenu element
private void Show(TangibleMenu TangibleMenuElement)
{
    App.Current.Dispatcher.Invoke(new Action(() =>
    {
        if (TangibleMenuElement.Shape.CheckAccess())
        {
            Debug.WriteLine("normal show");
            TangibleMenuElement.Shape.Opacity = 1;
            TangibleMenuElement.Shape.Visibility = System.Windows.Visibility.Visible;
            this.ParentContainer.Activate(TangibleMenuElement.Shape);
        }
        else
        {
            Debug.WriteLine("dispatcher show");
            TangibleMenuElement.Shape.Opacity = 1; // EXCEPTION HERE
            TangibleMenuElement.Shape.Visibility = System.Windows.Visibility.Visible;
            this.ParentContainer.Activate(TangibleMenuElement.Shape);
        }
    }));
}

答案 2 :(得分:0)

我的问题的解决方案:我访问了错误的Dispatcher ...

我没有注意Dispatcher.CurrentDispatcher和Application.Current.Dispatcher之间的区别。第一个返回当前线程的调度程序,第二个返回我的情况下的UI线程(应用程序的第一个线程)。

所以我的Timer线程收到了消息,名为Show(),要求一个Dispatcher并得到一个......但它是Timer线程的Dispatcher而不是UI线程。当我将代码更改为Application.Current.Dispatcher时,它按预期工作。

可以找到更详细的解释here