ここでは、新しい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]));
}
}
}
なぜ、これはどうしてですか?それはまったく後ろ向きのことです... –
なぜあなたはこれをしたいですか?私はあなたが他のスレッド上のコントロールと通信しようとすると問題が発生すると考えています。また、メッセージポンプから正常なメッセージを受信しません(リフレッシュのように) – slawekwin
データバインディングが機能します。しかし、コントロールが実際にバインディングですべてのプロパティを設定するまで表示されるまで、テンプレートは適用される必要があるかもしれません。コントロールのDispatcherを介してデリゲートを呼び出すと、スレッドで呼び出しが行われます。 Dispatcher.CurrentDispatcherは、myControl.Dispatcherと同じインスタンスを返す必要があります。これは、myControlが作成された同じスレッドでCurrentDispatcherが呼び出されるためです。 – Clemens