Доступ к потоку графического интерфейса из другого потока исключает исключение

109
15

Я пытаюсь отобразить элемент меню в своем приложении, как только появится конкретное сообщение Bluetooth. Сообщения собираются и интерпретируются по методу таймера, и если появляется правильное сообщение, элемент должен быть визуализирован. Я продолжаю получать исключение, сообщая мне, что объект принадлежит другому потоку и к нему нельзя получить доступ.

// 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 - это ScatterViewItem из Microsoft Surface SDK. У кого-нибудь есть предложения?

спросил(а) 2021-01-25T15:24:44+03:00 4 месяца, 2 недели назад
1
Решение
77

Решение моей проблемы: я обратился к неправильному диспетчеру...

Я не обращал внимания на разницу между Dispatcher.CurrentDispatcher и Application.Current.Dispatcher. Первый возвращает диспетчер для текущего потока, второй возвращает поток пользовательского интерфейса в моем случае (первый поток приложения).

Итак, моя тема Timer получила сообщение, называемое Show(), попросило диспетчера и получила один... но это был диспетчер потока Timer, а не поток пользовательского интерфейса. Когда я изменил код на Application.Current.Dispatcher он работал, как ожидалось.

Более подробное объяснение можно найти здесь.

ответил(а) 2021-01-25T15:24:44+03:00 4 месяца, 2 недели назад
45

TangibleMenuElement необходимо создать в потоке пользовательского интерфейса, а не просто добавить в контейнер в потоке пользовательского интерфейса. Это означает, что вам необходимо полностью FrameworkElement в потоке пользовательского интерфейса.

ответил(а) 2021-01-25T15:24:44+03:00 4 месяца, 2 недели назад
45

попробуй это


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

ответил(а) 2021-01-25T15:24:44+03:00 4 месяца, 2 недели назад
Ваш ответ
Введите минимум 50 символов
Чтобы , пожалуйста,
Выберите тему жалобы:

Другая проблема