C#,WPF,需要自动调用Dispatcher.Invoke吗?

6

我有一个带有Geospace地图嵌入的程序。为了使地图响应灵敏(例如,当单击地图时触发的事件),地图的事件处理在单独的线程上处理。

我的问题是,当地图触发事件时,我的程序需要更新其GUI中的一些内容,并调用回地图以处理在地图上放置图片等操作。

我尝试将整个事件处理程序方法包装在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
    }
2个回答

6
如果您需要让每个相应的操作在自己的同步上下文中保持不变,那么这是最佳方法。每当更新GUI时,您需要使用Dispatcher进行调用。
以下是一些使此过程更容易的建议:
1. 尝试批处理GUI操作。除了需要更少的代码(通过更少的调用),您还可以获得更好的性能。每个Dispatcher.Invoke调用都带有相当大的开销,因为它会将消息发布到Dispatcher的消息队列中,必须对其进行处理。
2. 考虑使用Dispatcher.BeginInvoke来避免阻塞,除非您真的需要等待。
3. 如果您可以使用.NET 4中的Task Parallel Library(或Rx Framework中的3.5sp1回退版本),则可以考虑重新设计以使用{{link1:任务实例与GUI线程同步}}。通过使用FromCurrentSynchronizationContext创建TaskScheduler,您可以更轻松地安排任务在GUI上运行,而不是使用Dispatcher Invoke调用。这也可以给您一些控制批处理的能力,因为您可以很容易地安排它们,并根据需要进行阻止/等待。

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接