我有一个嵌入了Geospace地图的程序。地图的事件处理在单独的线程上处理,以使地图保持响应(例如,单击地图时触发的事件)。
我遇到的问题是当地图触发事件时,我的程序需要更新其中的一些内容,并且还要回调地图以处理在地图上放置图片。
我尝试在this.Dispatcher.Invoke中包装整个事件处理程序方法,这使我回到主UI线程。这对于更新我的GUI非常有用,但是当我回调到地图时,我仍然在UI线程上,这可能会导致地图中出现一些问题。
基本上,为了使这项工作,每次我想要更改gui上的控件时,我将不得不运行dispatcher.invoke。有没有办法我可以自动执行此操作而不在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
}
答案 0 :(得分:6)
如果您需要将每个操作保留在自己的同步上下文中,那么这是最好的方法。每当更新GUI时,您都需要使用Dispatcher进行调用。
以下是一些使这更容易的建议:
尝试批量处理GUI操作。除了需要更少的代码(通过较少的调用调用),您将获得更好的性能。每个Dispatcher.Invoke调用都会带来相当大的开销,因为它会将消息发布到Dispatcher的消息队列中,并且必须进行处理。
考虑使用Dispatcher.BeginInvoke来避免阻止,除非你真的需要等待。
如果您可以使用.NET 4中的任务并行库(或Rx Framework中的backport到3.5sp1),您可能需要考虑重新处理它以使用Task instances synchronized to the GUI thread。通过使用FromCurrentSynchronizationContext创建TaskScheduler,您可以安排在GUI上运行的任务比Dispatcher Invoke调用更容易。这也可以让你对批处理有一些控制权,因为你可以很容易地安排它们,并根据需要阻止/等待。
答案 1 :(得分:2)
您可以使用PostSharp之类的内容,或尝试将您的UI更新压缩为单个方法调用,您可以调用一次并执行大量操作。或者甚至是这样的模式(它是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;
}
}
}