WPF Dispatcher.FromThread

本文详细介绍了在WPF应用程序中如何从非UI线程安全地更新UI元素,通过使用Dispatcher.FromThread方法获取正确的Dispatcher实例,并展示了如何在按钮点击事件中跨线程更新TextBlock的文本。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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;
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值