У меня есть программа с картой Геопространства, встроенной в него. Обработка событий для карты обрабатывается на отдельном потоке для хранения карты быстро реагирующей (например, события, которые стреляют, когда карта нажата).
Проблема, которую я имею, состоит в том, когда карта запускает событие, моя программа должна обновить некоторые вещи в, он - gui, и также перезвоните в карту для обработки помещающих изображений на карте.
Я пытался перенести весь метод обработчика событий в это. Диспетчер. Вызовите, который откладывает меня на основном потоке UI. Это работает отлично для обновления моего GUI, но когда я перезваниваю в карту, я нахожусь все еще на потоке UI, который может вызвать некоторые проблемы в карте.
В основном, для создания этой работы, я оказываюсь перед необходимостью выполнять dispatcher.invoke каждый раз, когда я хочу изменить управление на своем gui. Существует ли способ, которым я могу автоматически сделать это, не перенося каждый вызов в dispatcher.invoke? Я надеюсь, что это все имеет смысл.
Вот некоторый пример кода для события, о котором я говорю..
private void Map_OnMapClicked(object sender, MapClickedEventArgs e)
{
this.Dispatcher.Invoke(DispatcherPriority.Normal, (Action)(() =>
{
// Do something to update my gui
}));
Map.DoSomethingInTheMap();
this.Dispatcher.Invoke(DispatcherPriority.Normal, (Action)(() =>
{
// Do something to update my gui
}));
//etc etc etc
}
Если вам нужно сохранить каждую соответствующую операцию в ее собственном контексте синхронизации, это, к сожалению, лучший подход. Вам нужно будет вызывать с помощью Диспетчера всякий раз, когда вы обновляете свой графический интерфейс.
Вот несколько советов, как упростить эту задачу:
Попробуйте пакетировать свои операции с графическим интерфейсом пользователя. В дополнение к меньшему количеству кода (за счет меньшего количества вызовов вызовов) вы получите лучшую производительность. Каждый вызов Dispatcher.Invoke несет в себе изрядные накладные расходы, поскольку он отправляет сообщение в очередь сообщений Dispatcher, которое необходимо обработать.
Рассмотрите возможность использования Dispatcher.BeginInvoke, чтобы избежать блокировки, если вам действительно не нужно ждать.
Если вы можете использовать параллельную библиотеку задач из .NET 4 (или обратный порт на 3.5sp1 в Rx Framework), вы можете подумать о переработке этого, чтобы использовать экземпляры задач, синхронизированные с потоком графического интерфейса . Создав TaskScheduler с помощью FromCurrentSynchronizationContext, вы можете запланировать выполнение задач в графическом интерфейсе проще, чем вызовы Dispatcher Invoke. Это также может дать вам некоторый контроль над пакетной обработкой, так как вы можете легко запланировать их и заблокировать / подождать по мере необходимости.
Вы можете использовать что-то вроде PostSharp или попытаться сжать обновления пользовательского интерфейса до одиночных вызовов методов, когда вы вызываете их один раз и делаете много. Или даже такой шаблон (это Winforms, но идея та же):
private void UpdateToolStripItemText(ToolStripItem toolStripItem, string text)
{
if (InvokeRequired)
{
Invoke(new UpdateToolStripItemTextDelegate(UpdateToolStripItemText), new object[] { toolStripItem, text });
}
else
{
if (text != null)
{
toolStripItem.Text = text;
}
}
}