【问题标题】:BackgroundWorker.ReportProgress() not updating property and locking up the UIBackgroundWorker.ReportProgress() 不更新属性并锁定 UI
【发布时间】:2012-06-29 09:04:51
【问题描述】:

我正在使用backgroundWorker 进行长时间运行的操作:

BackgroundWorker backgroundWorker = new BackgroundWorker() { WorkerSupportsCancellation = true, WorkerReportsProgress = true };

backgroundWorker.RunWorkerCompleted += delegate(object s, RunWorkerCompletedEventArgs args)
{

};

backgroundWorker.ProgressChanged += delegate(object s, ProgressChangedEventArgs args)
{
    someViewModel.SomeProperty.Add((SomeObject)args.UserState);
};

backgroundWorker.DoWork += delegate(object s, DoWorkEventArgs args)
{
    someViewModel.SomeList.ForEach(x =>
    {
        someViewModel.SomeInterface.SomeMethod(backgroundWorker, someViewModel, someViewModel.SomeList, x);
    });
};

backgroundWorker.RunWorkerAsync();

然后在SomeInterface.SomeMethod:

public void SomeMethod(BackgroundWorker backgroundWorker, SomeViewModel someViewModel//....)
{
    //Filtering happens

    backgroundWorker.ReportProgress(0, someObjectFoundWhileFiltering);
}

所以,说到:

backgroundWorker.ProgressChanged += delegate(object s, ProgressChangedEventArgs args)
{
    someViewModel.SomeProperty.Add((SomeObject)args.UserState);//Adding the found object to the Property in the VM
};

someViewModel.SomeProperty.Add((SomeObject)args.UserState); 线上,SomeProperty 上的装置没有开火,UI 只是锁定。

我做错了什么?这是更新UI thread 的正确方法吗?

【问题讨论】:

  • 把 backgroundWorker.ReportProgress(0, someObjectFoundWhileFiltering);在 DoWork() 方法中。有什么理由在被调用的方法中?
  • SomeProperty 的类型是什么。您确定 Add 方法会触发事件(例如 NotifyPropertyChanged)。如何捕捉到 someviewmodel 对象中 SomeProperty 的变化?
  • 代码看起来基本OK,someViewModel.SomeProperty到底是什么?
  • @HenkHolterman someViewModel.SomePropertyList<EntityObject>
  • 您可能只是经常点击updateprogress。在那之前我已经把我的 GUI 锁起来了……顺便说一句;如果您对其执行.Add(),则该属性的“设置”不会触发...

标签: c# .net wpf multithreading backgroundworker


【解决方案1】:

我希望您正在开发一个 Windows 窗体应用程序,然后如果您要更新或发送一些值到您需要使用委托执行的表单组件,请将您的请求放在主线程 Q 中,请尝试这样你可能会找到解决办法。

【讨论】:

    【解决方案2】:

    对 winforms 控件的跨线程调用是危险的。它们可能导致不可预测的结果。 有时您会遇到特殊异常。有时 UI 只是没有重绘......在你的情况下,你正在挂起。

    为了避免这种情况,请像http://msdn.microsoft.com/en-us/library/ms171728.aspx 中所述那样调用 UI。 像这样:

    private void SetText(string text)
        {
            // InvokeRequired required compares the thread ID of the
            // calling thread to the thread ID of the creating thread.
            // If these threads are different, it returns true.
            if (this.textBox1.InvokeRequired)
            {   
                SetTextCallback d = new SetTextCallback(SetText);
                this.Invoke(d, new object[] { text });
            }
            else
            {
                this.textBox1.Text = text;
            }
        }
    

    请注意,此方法必须放入 UI 上下文中,因此 this 指的是 FromControl。 Invoke 将请求放入 UI 消息队列,然后由 UI 线程中运行的 UI 消息循环提取和处理。

    【讨论】:

      【解决方案3】:

      暂时找到了解决办法:

      深度克隆object

      backgroundWorker.RunWorkerCompleted += delegate(object s, RunWorkerCompletedEventArgs args)
      {
          ViewModel.SomeList = DeepClone<List<SomeObject>>(ViewModel.TempList);
      };
      
      backgroundWorker.ProgressChanged += delegate(object s, ProgressChangedEventArgs args)
      {
          var item = DeepClone<SomeObject>((SomeObject)args.UserState);
      
          ViewModel.TempList.Add(item);
      };
      
      public static T DeepClone<T>(T obj)
      {
          using (var ms = new MemoryStream())
          {
              var formatter = new BinaryFormatter();
              formatter.Serialize(ms, obj);
              ms.Position = 0;
      
              return (T)formatter.Deserialize(ms);
          }
      }
      

      【讨论】:

        猜你喜欢
        • 2020-02-11
        • 1970-01-01
        • 2016-08-07
        • 2014-04-16
        • 2021-08-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多