【问题标题】:Dispatcher.Invoke method doesn't work sometimesDispatcher.Invoke 方法有时不起作用
【发布时间】:2014-08-20 17:24:23
【问题描述】:

当我在 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没有更新,里面没有item,有时候usercontrol2的ListBox也会出现这种情况,我调试了一下,发现代码运行正常,就是ListBox.Items。添加方法运行,结果就是不出来。 如果我将 Dispatcher.Invoie 更改为 Dispatcher.BeginInvoke,则很正常。 有人知道原因吗?

【问题讨论】:

  • 如果这是你的真实代码,你根本不需要BackgroundWorker。您可以在StartWork 方法中直接将TextBlock 添加到Listbox。
  • 您创建了 BackgroundWorker,它应该在与 UI 没有连接的情况下工作,一旦启动,您就切换回 UI。先考虑一下。
  • 您对BackgroundWorker 的使用无效,因为您试图在UI 线程上运行DowWork 方法,但该方法的全部目的是它在后台线程上运行。
  • @Agent_L,你读过这个问题吗?

标签: c# wpf dispatcher


【解决方案1】:

首先,您对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);
}

【讨论】:

  • 问题是:为什么它有时会在 Invoke 上失败,但在 BeginInvoke 下工作。 Invoke 的外螺纹是如何创建的似乎无关紧要。
  • 报复性否决票,嗯?好吧,你真可怜……现在感觉好多了@Agent_L?问题作者说这是问题所在,有时usercontrol1中的ListBox没有更新...我正在帮助他们解决他们的问题,那怎么会不好?我建议你长大。
  • 这里没有任何报复性,我只是认为这不是一个好的答案。恕我直言,这是“如果您不知道如何修复损坏的部分,请修复其他内容”。他正在使用与他的UserControl 绑定的Dispatcher,这有什么问题?为什么要改成Application.Current
  • 似乎知道你在说什么......请随时提供你自己的答案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-08-16
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多