0

私は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ですか?

4

3 に答える 3

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 コンテキストに配置する必要があるため、これFromまたはControlを参照することに注意してください。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 に答える
0

Windowsフォームアプリケーションを開発していることを願っています。その後、デリゲートを使用して必要な値をフォームコンポーネントに更新または送信している場合は、リクエストをメインスレッドQに配置して、この方法で試してください。解決策が見つかるかもしれません。

于 2012-06-29T09:12:04.840 に答える