1

WinForm-Controls の更新時に「BeginInvoke」などの面倒を見る必要はないと考えたため、バックグラウンド操作には BackgroundWorker を使用したいと考えています。そうですか?私の知る限り、ProgressChanged および RunWorkerCompleted イベント ハンドラを使用して、WinForms コントロールを直接更新できます。

しかし、私はできませんが、次の例外が発生します:

作成されたスレッド以外のスレッドからアクセスされたコントロール コントロール名

いくつかのコード:

public partial class ConfigurationForm : Form
{

    public ConfigurationForm()
    {
        InitializeComponent();
        backgroundWorker1.WorkerReportsProgress = true;
        backgroundWorker1.WorkerSupportsCancellation = true;
        label1.Text = String.Empty;
        // [...]
    }

    private void StartButton_Click(object sender, EventArgs e)
    {
        if (backgroundWorker1.IsBusy != true)
        {
            label1.Text = "Converting...";
            backgroundWorker1.RunWorkerAsync();
        }
    }

    private void CancelButton_Click(object sender, EventArgs e)
    {
        if (backgroundWorker1.WorkerSupportsCancellation == true)
        {
            backgroundWorker1.CancelAsync();
        }
        progressBar1.Dispose();
        this.Close();
    }

    private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
    {
        progressBar1.Value = e.ProgressPercentage;
        // EXCEPTION here, why?
    }

    private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
    {
        BackgroundWorker worker = sender as BackgroundWorker;

        Converter c = new Converter();
        c.Start(worker, e);
    }

    private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        // EXCEPTION in all cases, why?
        if (e.Cancelled == true)
        {
            label1.Text = "Canceled";
        }
        else if (e.Error != null)
        {
            label1.Text = "Error: " + e.Error.Message;
        }
        else
        {
            label1.Text = "Done!";
        }
    }
}

これは WinForms アプリケーションではなく、VSTO PowerPoint アドインです。上記のフォームは、ユーザーが PowerPoint のリボン バーのアイコンをクリックすると、次のようにアドインによって作成されます。

//Do I need [STAThread] here? but doesn't seem to work anyway
private void button1_Click(object sender, RibbonControlEventArgs e)
{
    ConfigurationForm config = new ConfigurationForm();
    config.Show();
}

ここで何が問題なのか教えてもらえますか?

4

2 に答える 2

1

リンクを投稿しましたが、実際にはそれが最善の解決策だとは思いません。Application.Run() を呼び出していないか、Form.ShowDialog() を使用していないため、明らかに失敗が発生します。示されているようにコンテキストを明示的に割り当てることができますが、正しく行わないと非常に厄介な問題が発生する可能性があります。複数回割り当てるようなものです。

より良い修正は、自動的にインストールするように依頼することです。これにより、どのようなフォームを作成しても、それが以前に行われていない場合にのみインストールされるようになります。これをフォーム作成コードの前に置きます。

        WindowsFormsSynchronizationContext.AutoInstall = true;

コードが繰り返された場合に、そのコードの別のインスタンスを作成せず、スレッドの ExecutionContext を台無しにする可能性があるという大きな利点があります。

別の修正として ShowDialog() を検討してください。私が間違っていなければ、タブキーとショートカットのキーストロークにも問題があります。

于 2012-04-20T00:49:39.737 に答える
0

あなたの仮定は、Windows フォームでは正しいでしょう。それが機能する方法は、現在のスレッドの をBackgroundWorkers使用することです。SynchronizationContextWindows アプリでWindowsFormsSynchronizationContextは、マーシャリングを行う になります。

VSTO アプリでは、そうではありません。メソッドを実行するだけのデフォルトのものになるでしょう。Hans Passant からのリンクには、期待どおりに動作させるために必要なコードが含まれています。すなわち:

System.Threading.SynchronizationContext.SetSynchronizationContext(new WindowsFormsSynchronizationContext());

...create and start your background worker here...
于 2012-04-20T00:06:13.350 に答える