2016-08-24 3 views
-1

だから、バックグラウンドでSTAスレッドを実行していて、そこにユーザーコントロールを作成するとします。バックグラウンドスレッドでWPFコントロールを作成することの意義は何ですか?

どのように機能するのでしょうか?限界は何ですか?あなたはxpsファイルにビジュアルを書くことができますXpsDocumentと呼ばれる.NETのコンポーネントがあります:なぜ

_workingThread = new Thread(() => 
{ 
    //so far so good 
    var myControl = new MyCustomControl(); 

    //what happens if i set DataContext? Will databinding work? 
    //It looks like it does, but I am not entirely sure. 
    myControl.DataContext = new MyViewModel(); 

    //if databinding works, can I assume that at this point 
    //myControl's properties are already updated? 

    //what happens exactly if I invoke a delgate using Dispatcher property? 
    myControl.Dispatcher.Invoke(SomeMethod); 
    //or current dispatcher? 
    Dispatcher.CurrentDispatcher.BeginInvoke(SomeOtherMethod);   
}); 
_workingThread.SetApartmentState(ApartmentState.STA); 
_workingThread.Start(); 

は、質問に答えます。なぜ私はUIスレッドでそれを行う必要があります理由が表示されません。

+3

なぜ、これはどうしてですか?それはまったく後ろ向きのことです... –

+0

なぜあなたはこれをしたいですか?私はあなたが他のスレッド上のコントロールと通信しようとすると問題が発生すると考えています。また、メッセージポンプから正常なメッセージを受信しません(リフレッシュのように) – slawekwin

+3

データバインディングが機能します。しかし、コントロールが実際にバインディングですべてのプロパティを設定するまで表示されるまで、テンプレートは適用される必要があるかもしれません。コントロールのDispatcherを介してデリゲートを呼び出すと、スレッドで呼び出しが行われます。 Dispatcher.CurrentDispatcherは、myControl.Dispatcherと同じインスタンスを返す必要があります。これは、myControlが作成された同じスレッドでCurrentDispatcherが呼び出されるためです。 – Clemens

答えて

0

私は物事をテストするいくつかの時間を費やして、私はクレメンスのコメントは正確であったと思います。キーポイントは、次のとおり

  1. myControl.DispatcherDispatcher.CurrentDispatcherは、同一であり、両方のバックグラウンドスレッドのディスパッチャへの参照を保持します。ここに驚きはありません。
  2. 一般的に、Dispatcher.BeginInvokeコールは処理されないため、ディスパッチャが実行されていないとコントロールは正常に動作しません。あなたには2つの選択肢があります。バックグラウンドスレッドでDispatcher.Run()を呼び出し、呼び出す使用してコントロールを作成し、次のいずれかあなたがディスパッチャキューを処理したいとあなたのコントロールを「リフレッシュ」するたびに

    _backgroundDispatcher.BeginInvoke(new Action(() => 
    { 
        var myControl = new MyCustomControl(); 
        //do stuff 
    })); 
    

    または手動でpush dispatcher frameを。 XPSページの構築に関しては、両方のアプローチが実行可能です。

  3. コントロールがバックグラウンドスレッドで作成されていてもデータバインディングが機能します。しかし、場合によってはそれらは即時に適用されないため、ディスパッチャがキューを処理するまで待つ必要があります。

0

ここでは、新しいSTA Threadのウィンドウを作成するWPFアプリケーションの例を示します。私はそれに何の問題も見ません。スレッド名、ThreadId、Counter(INotifyPropertyChangedを介した変更)をいくつか出力しました。また、stackPanelCounterのバックグラウンドを、Timer Dispatcher.BeginInvokeから変更します。 XAML:

<Window x:Class="WpfWindowInAnotherThread.MainWindow" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
     xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
     mc:Ignorable="d" 
     SizeToContent="WidthAndHeight" WindowStartupLocation="CenterScreen" Title="WPF: Windows and Threads"> 
    <Grid> 
     <Grid.RowDefinitions> 
      <RowDefinition Height="Auto" /> 
      <RowDefinition Height="Auto"/> 
      <RowDefinition /> 
     </Grid.RowDefinitions> 
     <StackPanel Grid.Row="0" Orientation="Vertical"> 
      <TextBlock Text="{Binding ThreadId, StringFormat='ThreadId: {0}'}" /> 
      <TextBlock Text="{Binding ThreadName, StringFormat='ThreadName: {0}'}" /> 
     </StackPanel> 
     <StackPanel Grid.Row="1" Orientation="Horizontal" Name="stackPanelCounter"> 
      <TextBlock Text="Counter: " /> 
      <TextBlock Text="{Binding Counter}" /> 
     </StackPanel> 
     <StackPanel Grid.Row="2"> 
      <Button Name="btnStartInNewThread" Content="Start window in new Thread" 
        Click="btnStartInNewThread_Click"/> 
      <Button Name="btnStartTheSameThread" 
        Content="Start window in the same Thread" 
        Click="btnStartTheSameThread_Click" /> 
     </StackPanel> 
    </Grid> 
</Window> 

はコード:

using System; 
using System.ComponentModel; 
using System.Threading; 
using System.Windows; 
using System.Windows.Media; 
using System.Windows.Threading; 

namespace WpfWindowInAnotherThread 
{ 
    /// <summary> 
    /// Interaction logic for MainWindow.xaml 
    /// </summary> 
    public partial class MainWindow : Window, INotifyPropertyChanged 
    { 
     static int _threadNumber = 0; 
     readonly Timer _timer; 
     int _Counter; 

     public event PropertyChangedEventHandler PropertyChanged = delegate { }; 

     public int ThreadId 
     { 
      get { return Thread.CurrentThread.ManagedThreadId; } 
     } 
     public string ThreadName 
     { 
      get { return Thread.CurrentThread.Name; } 
     } 
     public int Counter 
     { 
      get { return _Counter; } 
      set { _Counter = value; PropertyChanged(this, new PropertyChangedEventArgs("Counter")); } 
     } 

     public MainWindow() 
     { 
      DataContext = this; 
      _timer = new Timer((o) => { 
       Counter++; 
       MainWindow wnd = o as MainWindow; 
       wnd.Dispatcher.BeginInvoke(new Action<MainWindow>(ChangeStackPanelBackground), wnd); 
      }, this, 0, 200); 
      InitializeComponent(); 
     } 
     private void btnStartTheSameThread_Click(object sender, RoutedEventArgs e) 
     { 
      MainWindow mainWnd = new MainWindow(); 
      mainWnd.Show(); 
     } 
     private void btnStartInNewThread_Click(object sender, RoutedEventArgs e) 
     { 
      Thread thread = new Thread(new ThreadStart(ThreadMethod)); 
      thread.SetApartmentState(ApartmentState.STA); 
      thread.IsBackground = true; 
      thread.Start(); 
     } 
     private static void ThreadMethod() 
     { 
      Thread.CurrentThread.Name = "MainWindowThread# " + _threadNumber.ToString(); 
      Interlocked.Increment(ref _threadNumber); 

      MainWindow mainWnd = new MainWindow(); 
      mainWnd.Show(); 

      Dispatcher.Run(); 
     } 
     private static void ChangeStackPanelBackground(MainWindow wnd) 
     { 
      Random rnd = new Random(Environment.TickCount); 
      byte[] rgb = new byte[3]; 
      rnd.NextBytes(rgb); 
      wnd.stackPanelCounter.Background = new SolidColorBrush(Color.FromArgb(0xFF, rgb[0], rgb[1], rgb[2])); 
     } 
    } 
} 
+0

私は実行中のディスパッチャを持っていません。新しいウィンドウが必要なのか、必要ないのですか。 –

+0

@NikitaB、私の不注意を許してください。あなたの状況では、別のスレッドでusercontrolを作成しているときに、これらのリンクが役に立ちます:[http://stackoverflow.com/questions/4884802/create-wpf-user-controls-in-other-thread](http ://stackoverflow.com/questions/4884802/create-wpf-user-controls-in-other-thread)と[マルチスレッドUI:HostVisual](https://blogs.msdn.microsoft.com/dwayneneed/2007/04)/26 /マルチスレッド-ui-hostvisual /) –

関連する問題