Dispatcher.FromThread 方法可以從線程中獲得 Dispatcher ,如果此線程中操作了UI相關的對象,如窗體,控件等,那麼它的返回值將不爲null, 否則爲null.
舉個例子:
新建一個wpf應用:默認窗體 MainWindow 裏放一個測試按鈕。
<Window x:Class="WpfApp1.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"
xmlns:local="clr-namespace:WpfApp1"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid>
<Button Width="100" Height="40" Content="test" Click="Button_Click" />
</Grid>
</Window>
再新建一個窗體 Window1,放一個textblock:
<Window x:Class="WpfApp1.Window1"
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"
xmlns:local="clr-namespace:WpfApp1"
mc:Ignorable="d"
Title="Window1" Height="450" Width="800">
<Grid>
<TextBlock x:Name="tb" Width="100" Height="40" />
</Grid>
</Window>
後臺代碼:
public partial class MainWindow : Window
{
private Window1 _win1;
private Thread _thread;
public MainWindow()
{
InitializeComponent();
Test();
}
public void Test()
{
_thread = new Thread(() =>
{
_win1 = new Window1();
_win1.ShowDialog();
});
_thread.SetApartmentState(ApartmentState.STA);//設置爲 STA 才能操作UI
_thread.Start();
}
}
按鈕測試代碼:
private void Button_Click(object sender, RoutedEventArgs e)
{
Dispatcher.Invoke(()=> {
_win1.tb.Text = "from thread";
});
}
這個時候,上面的代碼是沒法執行的,因爲 _win1 根本不在主UI線程,執行會crash.
改爲下面就正確了:
private void Button_Click(object sender, RoutedEventArgs e)
{
Dispatcher dispatcher = System.Windows.Threading.Dispatcher.FromThread(_thread);
dispatcher.Invoke(DispatcherPriority.Normal, new Action(() =>
{
_win1.tb.Text = "from thread";
}));
}
附:如果使用的是 Task ,是沒法直接設置 ApartmentState.STA 的,需要包裝一下,如:
private async Task<bool> Test()
{
return await StartSTATask<bool>(() =>
{
_win1 = new Window1();
_win1.ShowDialog();
return true;
});
}
private Task<T> StartSTATask<T>(Func<T> func)
{
var tcs = new TaskCompletionSource<T>();
_thread = new Thread(() =>
{
try
{
tcs.SetResult(func());
}
catch (Exception e)
{
tcs.SetException(e);
}
});
_thread.SetApartmentState(ApartmentState.STA);
_thread.Start();
return tcs.Task;
}