0

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

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吗?

4

3 回答 3

0

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

于 2012-06-29T09:12:04.840 回答
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 上下文中,因此指的是FromControl。Invoke 将请求放入 UI 消息队列,然后由 UI 线程中运行的 UI 消息循环提取和处理。

于 2012-06-29T11:16:31.057 回答
0

现在找到了解决方法:

深度克隆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);
    }
}
于 2012-07-05T12:44:47.887 回答