【问题标题】:Why does BackgroundWorker_RunWorkerCompleted not update GUI?为什么 BackgroundWorker_RunWorkerCompleted 不更新 GUI?
【发布时间】:2010-01-05 15:16:37
【问题描述】:

我已经搜索了论坛,但我认为没有适合我的问题的问题...

我使用 BackgroundWorker 来处理非常耗时的操作。此操作完成后,应将按钮设置为启用,以便用户可以执行其他操作。

我正在使用 WPF 并且遵循 MVVM 模式,因此我无法直接访问此按钮。我必须在 BackgroundWorker_RunWorkerCompleted 事件处理程序中调用一个方法,该方法将表示按钮启用状态的属性设置为 true。

这一切都很好,除了一件事:按钮仅在我之后重绘,例如单击窗口(或最大化窗口,...)。这很烦人,花了我一整天的时间来摆脱这种行为,但我找不到解决方案……

BackgroundWorker_RunWorkerCompleted 事件处理程序如下所示:

    void fileLoadBackgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) {
        SetButtonToEnabled(); }

有人知道如何解决这个问题吗?

编辑:

按钮绑定到一个命令:

<Button Name="btnLoadTargetFile" Command="{Binding Path=LoadTargetCommand}" .../>

此命令是 Smith 在他的博客 (http://msdn.microsoft.com/en-us/magazine/dd419663.aspx) 中所述的 RelayCommand,如下所示:

public RelayCommand LoadTargetCommand
    {
        get
        {
            if (loadTargetCommand == null)
            {
                loadTargetCommand = new RelayCommand(param => this.OnRequestLoadFile(BusinessLogic.CustomTypes.TreeType.Target), param => this.CanLoadTarget);
            }
            return loadTargetCommand;
        }
        set { loadTargetCommand = value; }
    }

this.CanLoadTarget 由 SetButtonToEnabled() 设置为 true;方法

编辑2:

以下代码“有效”:

fileLoadBackgroundWorker.RunWorkerAsync(argumentList);
while(fileLoadBackgroundWorker.IsBusy)
  System.Windows.Forms.Application.DoEvents();
SetButtonToEnabled();

但那是某种非常危险和丑陋的代码......

【问题讨论】:

  • 当您将属性设置为 true 时,您是否会引发 PropertyChanged 事件(即您的视图模型是否正确实现了 INotifyPropertyChanged)?
  • 如果我在 fileLoadBackgroundWorker.RunWorkerAsync() 之后调用该方法,一切正常,所以我认为这不是问题?!
  • 出于好奇,您是否对表单的形状或边框(边框颜色等)进行了任何 WMI 修改?
  • klausbyskov 可能是正确的/有一个好点。那么-您是否正确实施了 INotifyPropertyChanged ? :)
  • @md5sum:不,我没有! @benjamin:是的,我愿意 ;-) ...我将代码从非线程环境移植到当前,在我们开始使用 BackgroundWorker 之前一切正常

标签: c# wpf backgroundworker


【解决方案1】:

虽然不能解释你的问题,你可以尝试添加

System.Windows.Forms.Application.DoEvents();

Dispatcher.Invoke(new Action(delegate { }), DispatcherPriority.Background);

到您的 SetButtonToEnabled 函数调用结束(在您将按钮 Enabled 设置为 true 之后)。看起来后台工作人员正在调用 Complete 事件,但 GUI 没有刷新。

Here 是在 WPF 中使用 Backgroundworker 的完整示例。你可能想看看它,确保你的东西看起来一样。

您也可以查看Asynchronous Threading with Background Worker Object。这是使用 Dispatcher 和 Backgroundworker 的一个很好的例子

WPF Threading Model 是另一个值得查看的重要来源。

【讨论】:

  • 感谢您的评论!我的代码看起来像示例,除了因为我使用的 MVVM 模式,我无法直接访问按钮
  • 您能否发布 SetButtonToEnabled 的代码。我不认为这是后台工作人员的问题,因为您提到 Complete 确实被调用了。它可能是你在主线程上做的事情。当进程在后台运行时你在做什么?
  • 您可能想查看 InvalidateRequerySuggested:msdn.microsoft.com/en-us/library/… 尝试将其添加到 SetButtonToEnabled 的末尾
  • 非常感谢您的链接,CommandManager.InvalidateRequerySuggested() 的调用修复了它!
【解决方案2】:

您的问题可能与 BackgroundWorker 无关。如果您直接从主线程调用SetButtonToEnabled 方法,您可能会看到相同的行为。将对RunWorkerAsync 的调用替换为对SetButtonToEnabled 的调用以对此进行测试。

一些评论者建议您查看您的 INotifyPropertyChanged 实现,这听起来是个好建议。

【讨论】:

  • 感谢您的回答!如果我在主线程中调用 SetButtonToEnabled 一切正常...
  • 你能确认 RunWorkerCompleted 事件正在引发吗?你在那里设置的断点会被命中吗?
  • 我能想到的唯一另一件事是确认事件处理程序正在主线程上执行。
  • 在 SetButtonToEnabled 中,检查 Button 的 InvokeRequired 属性是否为真
  • 实际上对于 WPF,看起来你检查了 Dispatcher,所以像这样:btnRefresh.Dispatcher.CheckAccess()。看到这个帖子:diranieh.com/NET_WPF/Threading.htm
猜你喜欢
  • 2013-12-27
  • 1970-01-01
  • 2016-02-01
  • 1970-01-01
  • 1970-01-01
  • 2010-11-02
  • 1970-01-01
  • 1970-01-01
  • 2021-12-18
相关资源
最近更新 更多