3

長い投稿で申し訳ありませんが、混乱が生じないように問題を詳細に説明しようとしました。最後の文には実際の質問が含まれています。

C#/。NETを使用してマルチスレッドアプリケーションをプログラミングしています。

このアプリケーションは、圧力センサーからのデータを視覚化するメインウィンドウで構成されています。センサーデータは独自のスレッドで取得されます。

データはクラスのインスタンスにも記録されますListView

ここに画像の説明を入力してください

「保存」ボタンを使用して、ログに記録されたデータをディスク上のファイルに保存する可能性があります(.NETクラスのインスタンスを開く必要がありますSaveFileDialog)。

これSaveFileDialogも独自のスレッドで実行されています。メソッドを呼び出すときに問題が発生しますSaveFileDialog.ShowDialog()

System.InvalidOperationExceptionが処理されませんでしたMessage="クロススレッド操作が無効です:コントロール'tlpMain'は、作成されたスレッド以外のスレッドからアクセスされました。" Source = "System.Windows.Forms"

SaveFileDialogの所有者(メインウィンドウ)が別のスレッドで実行されているため、問題が発生します。

SaveFileDialog()のスレッドを作成するコードは次のとおりです。

private void bSave_Click(object sender, EventArgs e)
{
    Thread saveFileDialog = new Thread(OpenSaveFileDialog);
    saveFileDialog.SetApartmentState(ApartmentState.STA);
    saveFileDialog.Start();
}

メソッドOpenSaveFileDialog()のコード:

private void OpenSaveFileDialog()
{
    SaveFileDialog saveFileDialog = new SaveFileDialog();
    saveFileDialog.Filter = "Text Files (*.txt)|*.txt|CSV (*.csv)|*.csv|All Files (*.*)|*.*";
    saveFileDialog.FilterIndex = 0;

    /* Call "ShowDialog" with an owner ("this.Parent") to achieve, so that
     * the parent window is blocked and "unclickable".
     * 
     * Danger of an "InvalidOperationException" because "this.Parent" control
     * is running (was created) in another thread.
     * But "this.Parent" should not be modified by this method call.
     */
    DialogResult pressedButton = saveFileDialog.ShowDialog(this.Parent);
    ...

InvalidOperationExceptionは、 VisualStudioのデバッガーでアプリケーションを実行している場合にのみスロー/表示されます。これまでのところ、アプリケーションを「正常に」実行する場合は問題ありません。

しかし、私はこの問題を避けたいと思います。

ラッパーメソッド(SaveFileDialog)を作成しようとしました:

private void OpenSaveFileDialog()
{
    SaveFileDialog saveFileDialog = new SaveFileDialog();
    ...
    SaveFileDialog(saveFileDialog, this.Parent);
}

ラッパーメソッド:

private void SaveFileDialog(SaveFileDialog saveFileDialog, Control owner)
{
    if (owner.InvokeRequired)
        BeginInvoke(new dSaveFileDialog(SaveFileDialog), new object[] { saveFileDialog, owner });
    else
    {
        DialogResult pressedButton = saveFileDialog.ShowDialog(owner);
        ...

これによりTargetInvocationExceptionMain()メソッドには次のラベルが付けられ[STAThreadAttribute]ますが、

InnerException:System.Threading.ThreadStateException Message = "OLE呼び出しを行う前に、現在のスレッドをシングルスレッドアパートメント(STA)モードに設定する必要があります。メイン関数にSTAThreadAttributeがマークされていることを確認してください。この例外は、デバッガーがプロセスに添付されています。」Source = "System.Windows.Forms"

SaveFileDialog(スレッド)の問題を起こさずにメインウィンドウがブロックされる(「クリックできない」)ように、ある方法でを開く方法の手がかりを持っている人はいますか?

ありがとうございました。

4

3 に答える 3

2

デバッグ中に発生するスレッド間例外はManaged Debugging Assistantです。通常、これらはデバッガーの外ではアクティブになりません。これは、Visual Studio の外部でアプリケーションを実行したときに表示されない理由を説明しています。

メインの UI スレッド以外のスレッドから UI 要素に対して何もできないことを自分で発見したようです。またはISynchronizeInvokeメソッドを使用して操作の実行を UI スレッドにマーシャリングし、UI 要素に安全にアクセスできるようにします。InvokeBeginInvoke

ただし、コードにはまだ問題があります。OpenSaveFileDialogワーカー スレッドで実行されているメソッドでは、もちろん UI 要素であるコンストラクターを呼び出していますSaveFileDiaglog。これはできません。繰り返す価値があります。ワーカー スレッドに対して、またはワーカー スレッドから何も行うことはできません。これには、コンストラクターの呼び出しが含まれます。FormControl

于 2011-05-20T13:24:13.600 に答える
1

返事が遅れて申し訳ありません。

まず第一に、迅速かつ有益な回答に感謝します。

ありえないヒント

ワーカー スレッドからフォームまたはコントロールに対して何かを行う

私を大いに助けてくれました。

私は通常、Microsoft の Windows の GUI プログラミングを行っていないので、あまり詳しくありません。

そこで、実際の問題 (ワーカー スレッドから GUI を実行するのではなく) を解決し、クリーンで論理的なコード構造を持ちたいと考えたため、以前のソース コードを再検討しました。

したがって、ウィンドウのコンポーネント オブジェクト モデル (COM) と使用されるスレッド モデルのトピックを読みました。

コードは次のようになります。

メイン ウィンドウ(「UI スレッド」) が開始されます。ApartmentState STA

...
ThreadStart threadStart = delegate { RunMainWindow(mainWindow); };
Thread mainWindowThread = new Thread(threadStart);

mainWindowThread.SetApartmentState(ApartmentState.STA);
mainWindowThread.Start();
...

「保存」ボタンのイベント ハンドラー (メイン ウィンドウ):

private void bSave_Click(object sender, EventArgs e)
{
            OpenSaveFileDialog();
}

メソッド " OpenSaveFileDialog " (メイン ウィンドウ):

private void OpenSaveFileDialog()
{
            SaveFileDialog saveFileDialog = new SaveFileDialog();
            ...

            DialogResult pressedButton = saveFileDialog.ShowDialog();
            ...
}

最適化の余地はまだあります (確かに) が、私はこの予備的な結果に満足しています。

あなたの助けに感謝します。

于 2011-05-23T12:59:12.300 に答える
0

この Microsoft ブログ投稿に従ってください: http://blogs.msdn.com/b/smondal/archive/2011/05/11/10059279.aspx

2 つの方法だけで完了です。

于 2012-10-24T07:50:59.443 に答える