BackgroundWorker.ReportProgress()不更新属性并锁定UI

时间:2012-06-29 09:04:51

标签: c# .net wpf multithreading backgroundworker

我正在使用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

的正确方法吗?

3 个答案:

答案 0 :(得分:0)

我希望您正在开发一个Windows窗体应用程序,然后如果您正在使用委托更新或向表单组件发送一些值,请将您的请求放入主线程Q,尝试通过这种方式你可以找到解决方案。

答案 1 :(得分:0)

对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上下文中,因此指的是来自控制。 调用将请求放入UI消息队列,然后通过在UI线程中运行的UI消息循环进行提取和处理。

答案 2 :(得分:0)

现在找到一个解决方法:

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