从其他线程访问 GUI 线程会引发异常

本文关键字:线程 异常 GUI 其他 访问 | 更新日期: 2023-09-27 18:36:49

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

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

我认为这个确切的问题可以通过使用调度程序来解决,但在这种情况下,它似乎不起作用。 TangibleMenuElement.Shape是来自Microsoft Surface SDK的ScatterViewItem。有人有什么建议吗?

从其他线程访问 GUI 线程会引发异常

需要在 UI 线程

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

我的问题的解决方案:我访问了错误的调度程序...

我没有注意Dispatcher.CurrentDispatcher

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

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

可以在此处找到更详细的解释。

试试这个

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