31

アプリケーションSystem.Windows.Threading.Dispatcherの UI スレッドで動作しますか?WinForms

はいの場合、なぜですか? コンポーネントのように見える WindowsBase.dll から来ていWPFます。

そうでない場合、どうすれば作業ユニットを UI スレッドに戻すことができますか? を見つけましControl.BeginInvoke()たが、元のスレッドを参照するためだけにコントロールを作成するのは不器用です。

4

7 に答える 7

27

DispatcherWinFormsアプリでも使えます。

確実に UI スレッド (button.Click ハンドラーなど) にDispatcher.CurrentDispatcherいる場合は、後で通常どおりバックグラウンド スレッドから UI スレッドにディスパッチするために使用できる UI スレッド ディスパッチャーを提供します。

于 2009-07-21T15:42:42.020 に答える
13

DispatcherはWPFコンポーネントであり、WinFormsコンポーネントではありません。

UIスレッドで作業項目をディスパッチする場合は、既に見つけたControl.BeginInvokeを使用するか、スレッド間でResetEvents/WaitObjectsに反応する必要があります。

通常、UIスレッドで作業項目を呼び出すことは、それがUI作業(つまり、コントロールのコンテンツなどの更新)でない限り、悪いことです。その場合、Control.BeginInvoke()で十分です。

于 2008-11-19T20:17:10.923 に答える
11

あなたの質問に対する以前の回答以来、「WinFormsでTPLを使用した並列プログラミング」という質問への回答で、System.Windows.Threading.Dispatcher Windowsフォームでの使用の例を提供しました。

UI スレッド (たとえば、button.Click ハンドラー) にいることが確実な場合、Dispatcher.CurrentDispatcher は、通常どおりバックグラウンド スレッドから UI スレッドにディスパッチするために使用できる UI スレッド ディスパッチャーを提供します。

誤解を招くか混乱を招くか、具体的な使用状況が欠けている:

  • button.Clickハンドラーが UI スレッド上にあることを保証しません。
  • UI スレッドを使用していない場合でも、WinForms フォームの UI スレッドのディスパーチャーを使用できます。

WinForm UI スレッドのディスパッチャーを取得できます。

Dispatcher dispatcherUI = Dispatcher.CurrentDispatcher;

ボタンクリックイベントハンドラーまたはその他の場所(フォームコンストラクター内)

そして、それを使用して他のスレッドから UI で実行します。私の回答で以下の例の詳細を参照してください。

private void button1_Click(object sender, EventArgs e)
{
  Dispatcher dispUI = Dispatcher.CurrentDispatcher;
  for (int i = 2; i < 20; i++)
  {
    int j = i;
    var t = Task.Factory.StartNew
           (() =>
      {
        var result = SumRootN(j);
        dispUI.BeginInvoke
            (new Action
                 (() => richTextBox1.Text += "root " + j.ToString()
                       + " " + result.ToString() + Environment.NewLine
                 )
             , null
            );
      }
           );
}
于 2013-04-15T04:30:26.543 に答える
1

バックグラウンド ワーカー スレッドは UI メッセージ ポンプに対応しているため、使用します。この MSDN の記事では、主に WPF について説明していますが、BWT は Windows フォームに対しても UI 対応であると述べています。

于 2008-11-19T20:31:50.333 に答える
1

Winforms内の独自のスレッドで実行されるOracle依存関係クラスを使用して、同様の問題が発生しました。

OnChange イベントが Oracle Dependency から発生したとき、DataSource を eventargs.Details (本質的には DataTable) に設定するだけで DataGridView の変更を表示したかったのですが、次のメッセージがスローされます: System.InvalidOperationException was unhandled by user code Message=Cross-thread operation無効: コントロール 'dataGridView1' は、それが作成されたスレッド以外のスレッドからアクセスされました。

StackOverflow ユーザーの Brian Peiris (bpeiris@gmail.com) は、私の同僚がこの方法を教えてくれました。

void dep_OnChange(object sender, OracleNotificationEventArgs arg)
         {
         Console.WriteLine("Notification received");

         int infoSum = int.Parse(arg.Details.Compute("Sum(Info)", "Info is not null").ToString());
         InfoSum x = (InfoSum)infoSum;
         foreach (DataRow dr in arg.Details.Rows)
            {
            Console.WriteLine(string.Format("Operation(InfoSum)= {0}", Enum.GetName(typeof(InfoSum), x)));
            Console.WriteLine(string.Format("ontable={0}  Rowid={1},info={2}", dr.Field<string>("ResourceName"), dr.Field<string>("rowid"), dr.Field<Int32>("info")));
            }
         // Following  will throw cross-thread 
         // dataGridView1.DataSource = arg.Details;
         // instead of line above use the following
         dataGridView1.BeginInvoke((Action)(()=>dataGridView1.DataSource = arg.Details));
         IsNotified = true;
         }

      }
于 2012-09-27T20:29:34.340 に答える
0

場合によっては、Timer コンポーネントが便利で、WinForms で簡単にセットアップできます。間隔を設定してから有効にし、Tick イベント ハンドラーで最初に行うことは、それ自体を無効にすることです。

Timer は独自のスレッドでコードを実行すると思うので、アクションを実行するには、BeginInvoke (WinForm オブジェクト [this] に対して呼び出される) を実行する必要があるかもしれません。

private WebBrowserDocumentCompletedEventHandler handler; //need to make it a class field for the handler below (anonymous delegates seem to capture state at point of definition, so they can't capture their own reference)
private string imageFilename;
private bool exit;

public void CaptureScreenshot(Uri address = null, string imageFilename = null, int msecDelay = 0, bool exit = false)
{
  handler = (s, e) =>
   {
     webBrowser.DocumentCompleted -= handler; //must do first

     this.imageFilename = imageFilename;
     this.exit = exit;

     timerScreenshot.Interval = (msecDelay > 0)? msecDelay : 1;
     timerScreenshot.Enabled = true;
   };

  webBrowser.DocumentCompleted += handler;
  Go(address); //if address == null, will use URL from UI
}

private void timerScreenshot_Tick(object sender, EventArgs e)
{
  timerScreenshot.Enabled = false; //must do first

  BeginInvoke((Action)(() => //Invoke at UI thread
  { //run in UI thread

    BringToFront();
    Bitmap bitmap = webBrowser.GetScreenshot();

    if (imageFilename == null)
      imageFilename = bitmap.ShowSaveFileDialog();

    if (imageFilename != null)
    {
      Directory.CreateDirectory(Path.GetDirectoryName(Path.GetFullPath(imageFilename))); //create any parent directories needed
      bitmap.Save(imageFilename);
    }

    bitmap.Dispose(); //release bitmap resources

    if (exit)
      Close(); //this should close the app, since this is the main form

  }), null);
}

WebCapture ツール ( http://gallery.clipflair.net/WebCapture、ソース コード: http://ClipFlair.codeplex.com、Tools/WebCapture フォルダーを参照) で上記の動作を確認できます。ところで、コマンド ラインから実行可能ファイルを呼び出す場合は、プロジェクトの [プロパティ] に移動し、[セキュリティ] タブで ClickOnce セキュリティをオフにしてください (そうしないと、コマンド ラインにアクセスできません)。

于 2013-08-25T15:34:43.837 に答える
0

backgrounderを見て、ニーズに合っているかどうかを確認してください。

于 2009-10-14T23:15:06.277 に答える