34

長い遅延の更新

私はこの質問に対するMUG4Nの回答を受け入れています。また、MUG4Nに対して提起されたいくつかの批判にも対応したいと思います。

ChrisFは言った:

...バックグラウンドスレッドから直接UI呼び出しを行うことはできません。

これは包括的な声明であり、100%真実ではありません。いくつかの事実を指摘させてください。

  1. を設定すると、実際に必要なすべてのUI呼び出しを行うことができますControl.CheckForIllegalCrossThreadCalls = false「わかった!」あなたが言っているのを聞きます。「そんなことしない!」はい、はい-しかし、なぜですか?答え:これは時々メモリを破壊するからです。

    の制御クラスはSystem.Windows.Formsスレッドセーフになるように記述されていないため、バックグラウンドスレッドから更新するとメモリが破損する場合があります。しかし、これがたまにしか発生せず、常に発生するわけではない場合、これは、UIコード自体の呼び出しではなく、例外を引き起こす可能性のあるUIコードの潜在的に危険な衝突であるということを示しています。

  2. ポイント1を補強するために、これを考慮してください。バックグラウンドスレッドからUIコードを呼び出す「安全な」方法は、Control.Invokeまたはを使用して呼び出すことControl.BeginInvokeです。しかし、これUI呼び出しです; これは、GUI以外のスレッドからGUIを更新する場合に行うことになっているUI呼び出しにすぎません。私が言いたいのは、明らかに、Control混乱を引き起こすのは、外部スレッドからオブジェクトに対して「任意の」メソッドを呼び出すだけではないということです(その場合、呼び出すことさえできず、Invoke完全にスタックします) 。繰り返しになりますが、破壊的であることが判明するのは、同時に安全に発生できない個別のUI呼び出しの潜在的な衝突です。

  3. 上記の2つの点を念頭に置いて、自分自身にMessageBox.Show問いかけてください。GUI以外のスレッドから呼び出すのはなぜ安全ではないのでしょうか。完全に分離されたFormものが作成され、表示されます。そのプロパティは、他の既存のGUIオブジェクトとはまったく相互作用しません。実際、そのプロパティにアクセスする呼び出し元のスレッドから(そしてメソッドの戻り値を介してのみ)、1つを除いて、どのような方法でもどこにもアクセスできません。DialogResultShow

一緒に移動します。コンラートアルブレヒトは言った:

... Show()がDanのref'dトピックに独自のメッセージポンプを設定するという主張を考えると(これは実証されていませんが、私は反論できません)...

これは完全に公正な点です(私は個人的にJared Parを十分に高く評価しているので、彼の言うことを疑う傾向はありません)。いずれにせよ、 ReflectorMessageBox.Showを介してメソッドを覗くと、このスニペットが明らかになります。

Application.BeginModalMessageLoop();
try
{
    result = Win32ToDialogResult(SafeNativeMethods.MessageBox(new HandleRef(owner, zero), text, caption, type));
}
finally
{
    Application.EndModalMessageLoop();
    UnsafeNativeMethods.ThemingScope.Deactivate(userCookie);
}

メソッドをさらに覗くと、Application.BeginModalMessageLoopこれが明らかになります。

ThreadContext.FromCurrent().BeginModalMessageLoop(null);

そしてこれThreadContext.FromCurrentは、順番に:

// [Reflector shows that currentThreadContext is a ThreadStatic member. -Dan]
if (currentThreadContext == null)
{
    currentThreadContext = new Application.ThreadContext();
}
return currentThreadContext;

このコードを完全に理解するためのこれらの低レベルのWindows構造については十分にわかりませんが、これは、以前のコメントで参照した回答でJaredが言っていたことの証拠であるように思われます(好奇心旺盛な読者の場合:MessageBoxを実行します。 Show()は自動的にUIスレッドにマーシャルしますか?)。

だから、ええ。私はこれについてMUG4Nに完全に同意します。

(私がまだここで間違っていると誰かが説得力を持って主張できる場合は、声を上げてください。MUG4Nが正しいと信じる理由についてはかなり良い主張をしたと思いますが、100%確実ではありません。)


元の質問

多くの場合、何かが発生したことをユーザーに通知したいだけですが、実際にはユーザーからの入力は必要ありません。この一般的なシナリオでは、次のようなコードが表示されることがあります。

MessageBox.Show("Something has occurred", "Something", MessageBoxButtons.OK);

このコードは、ご存知のとおり、[ OK ]ボタンだけで小さなポップアップウィンドウを表示します。これが問題です:このコードブロック(UIスレッド)。しかし、ほとんどの場合、 [ OK ]ボタンしかない場合は、ブロックする必要はほとんどないように思われます。(通常、ブロックの目的はユーザーからの入力を受け取ることではありませんか?ユーザーの唯一の選択肢が「OK」である場合、この典型的なケースでは、ブロックはかなり無意味ではありませんか?)

明らかにMessageBox.Show、何も返さず(no DialogResult)、ブロックしないことを除いて、基本的に正確に実行する独自の小さなフォームを作成できます。でも、知らなかったこのようなものがすでに存在するのではないかと思っていました。

4

4 に答える 4

13

このタスクを実行するには、マルチスレッドを使用する必要があります。このタスクでは、一方のスレッド(メインスレッド)が処理を実行し、もう一方のスレッドを使用してメッセージボックスを表示します。

于 2010-05-14T12:43:02.000 に答える
7

NotifyIconをアプリケーションに追加して、バルーンのヒントを表示するのはどうですか?欠点は、通知がすぐに消えることですが、ユーザーがアクションを実行する必要がない場合は、それがユーザーにとって最適な場合があります。

この質問にはさらに多くの提案があります。

于 2010-05-14T18:20:49.040 に答える
2

私が試したいのは、Win32APIからMessageBox関数を直接呼び出すことです。

using System.Runtime.InteropServices;

[DllImport("User32.dll")]
public static extern int MessageBox(int h, string m, string c, int type);

nullハンドルとAPPLMODALタイプを使用してみてください。それはうまくいくかもしれません。

于 2010-05-14T18:29:41.663 に答える
0

それは古い質問ですが、それでも...

1)IWshShellをインポートします(「Windowsスクリプトホストオブジェクトモデル」)

Dim wsh As New IWshRuntimeLibrary.WshShell wsh.Popup(String.Concat(Me.GetType.FullName、vbCrLf、_ Application.ExecutablePath)、0.75、 "Title"、MessageBoxButtons.OKCancelまたはMessageBoxIcon.Question)

イェンス...

于 2013-04-30T16:19:00.887 に答える