WPF Dispatcher.FromThread

Dispatcher.FromThread 方法可以从线程中获得 Dispatcher ,如果此线程中操作了UI相关的对象,如窗体,控件等,那么它的返回值将不为null, 否则为null.

举个例子:

新建一个wpf应用:默认窗体 MainWindow 里放一个测试按钮。


    
        

再新建一个窗体 Window1,放一个textblock:


    
        
    

后台代码:

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 Test()
{
	return await StartSTATask(() => 
	{
		_win1 = new Window1();
		_win1.ShowDialog();
		return true;
	});
}

private Task StartSTATask(Func func)
{
	var tcs = new TaskCompletionSource();
	_thread = new Thread(() =>
	{
		try
		{
			tcs.SetResult(func());
		}
		catch (Exception e)
		{
			tcs.SetException(e);
		}
	});
	_thread.SetApartmentState(ApartmentState.STA);
	_thread.Start();
	return tcs.Task;
}

 

你可能感兴趣的:(WPF)