Dispatcher.Invoke方法有时不起作用

时间:2014-08-20 08:59:27

标签: c# wpf dispatcher

当我在wpf中使用dispatcher.invoke方法时,我遇到了一个非常奇怪的问题。

背景:

我定义了一个用户控件,有一个DoWorkEventArgs支持一些异步工作:

public class MyUserControl : UserControl
{
    private BackgroundWorker bw;

    public MyUserControl()
    {
        bw.DoWork += new DoWorkEventHandler(DoWorkMethod);
    }

    public void StartWork()
    {
        bw.RunWorkerAsync();
    }

    void DoWorkMethod(object sender, DoWorkEventArgs e)
    {
        this.Dispatcher.Invoke((System.Action)delegate()
        {
            //Add some item in a ListBox, this ListBox is defined in the user control.
            TextBlock b = new TextBlock();
            //some code
            Listbox.Items.Add(b);
        }
    }
}

单击按钮时,我创建了此用户控件的2个实例并调用StartWork方法:

MyUserControl control1 = new MyUserControl();
MyUserControl control2 = new MyUserControl();

control1.StartWork();
control2.StartWork();

这是问题,有时候usercontrol1中的ListBox没有更新,其中没有项目,有时这种情况发生在usercontrol2的ListBox中,我调试它们,我发现代码运行正常,ListBox.Items。添加方法运行,结果不会出来。 如果我将Dispatcher.Invoie更改为Dispatcher.BeginInvoke,那么它是正常的。 有人知道原因吗?

1 个答案:

答案 0 :(得分:0)

首先,您对BackgroundWorker的使用无效,因为您尝试在UI线程上运行DowWork方法,但该方法的全部目的是它在后台线程上运行。如果您想知道如何正确实现BackgroundWorker,请在Stack Overflow上查看我对How to correctly implement a BackgroundWorker with ProgressBar updates?问题的回答。

但是,如果您只是想异步运行某些代码,那么这些天你真的不需要使用BackgroundWorker。相反,您可以使用Task class执行以下操作:

Task.Factory.StartNew(() => NameOfMethodToRunAsynchronously);

如果您需要在UI线程上运行部分NameOfMethodToRunAsynchronously方法,那么您可以返回Dispatcher.Invoke来电:

private void NameOfMethodToRunAsynchronously()
{
    // Some long running process
    Dispatcher.Invoke((System.Action)delegate()
    {
        //Add some item in a ListBox, this ListBox is defined in the user control.
        TextBlock b = new TextBlock();
        //some code
        Listbox.Items.Add(b);
    }
}

最后,要回答您对Dispatcher课程的原始问题,请参阅MSDN上的Dispatcher Class页面。从该页面:

  

提供管理线程工作项队列的服务。

请注意,它表示一个线程而不是 UI线程。这意味着可以成为您想要的UI线程,但不一定如此。为了确保它将用于UI线程,我们可以简单地在MainWindow.xaml.cs的构造函数中的UI线程上设置它:

Dispatcher uiDispatcher = Application.CurrentDispatcher;

因此,为了确保您的Dispatcher能够在UI线程上运行,只需使用该实例:

uiDispatcher.Invoke((System.Action)delegate()
{
    //Add some item in a ListBox, this ListBox is defined in the user control.
    TextBlock b = new TextBlock();
    //some code
    Listbox.Items.Add(b);
}