0

私はこのコードを持っています:

public void Blah(IWin32Window _this)
{
    for (int i = 0; i < item_quantity; i++)
    {
        try { File.Delete(item[0, i]); }
        catch (Exception ex)
        {
            if (MessageBox.Show(_this, String.Format("Error while accessing {0}\n{1}"
                , item[0, i], ex.Message), "Error", MessageBoxButtons.RetryCancel
                , MessageBoxIcon.Error) == DialogResult.Retry)
            { i--; }
        }
    }
}

...そしてメイン UI スレッドのこのコード:

private void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
    AnotherClass.Blah(this);
}

このコードを実行すると、安全でないクロススレッド例外が発生します。この操作を行う安全な方法は何ですか?

4

4 に答える 4

1

設計を容認しているわけではありませんが、フォームを Blah() に渡してから、参照されているフォームに対して Invoke() を渡すことができます。

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }

    private void button1_Click(object sender, EventArgs e)
    {
        if (!backgroundWorker.IsBusy)
        {
            button1.Enabled = false;
            backgroundWorker.RunWorkerAsync();
        }
    }

    private void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
    {
        SomeClass AnotherClass = new SomeClass();
        AnotherClass.Blah(this);
    }

    private void backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        button1.Enabled = true;
        MessageBox.Show("Done!");
    }

}

public class SomeClass
{
    public void Blah(Form frm)
    {
        int item_quantity = 5;

        for (int i = 0; i < item_quantity; i++)
        {
            try
            {
                //File.Delete(item[0, i]);

                Console.WriteLine("i = " + i.ToString());
                throw new Exception("duh");
            }
            catch (Exception ex)
            {
                frm.Invoke(new Action(() =>
                    {
                        DialogResult result = MessageBox.Show(frm, String.Format("Error while accessing {0}\n{1}", "something", ex.Message), "Error", MessageBoxButtons.RetryCancel, MessageBoxIcon.Error);
                        if (result == DialogResult.Retry)
                        {
                            i--;
                        }
                    }));
            }
        }
    }
}
于 2013-06-03T16:59:37.430 に答える
1

バックグラウンド スレッドで UI 作業を実行しようとしているため、クロススレッド例外が発生します。デリゲートによってスローされる例外を保持するRunWorkerCompletedEventArgsというプロパティがあります。のハンドラーを設定し、プロパティに値があるかどうかを確認します。その場合は、その時点で UI スレッドにいるため、ハンドラーでプロンプトを表示します。シナリオでのメソッドを再度呼び出します。ErrorRunWorkerAsyncRunWorkerCompletedBackgroundWorkerErrorMessageBoxBackgroundWorkerRunWorkerAsyncDialogResult.Retry

(おそらく、 and の値を調整してBackgroundWorkerAnotherClass.Blahへのi2 回目の呼び出しのループ条件を準備する必要がありますBackgroundWorker。には、その値を渡すために使用できるDoWorkEventArgsと呼ばれるプロパティがあります。)Argument

于 2013-06-03T15:14:27.943 に答える
0

別のスレッドから呼び出すときは、次のような UI コードを実行する必要があります。

// must use invoke because the timer event is running on a separate thread
this.Invoke(new Action(() =>
{
     MessageBox.Show("Message");
}));
于 2013-06-03T15:16:25.963 に答える