一种WPF在后台线程更新UI界面的简便方法
WPF框架规定只有UI线程(主线程)可以更新界面,所有其他后台线程无法直接更新界面。幸好,WPF提供的SynchronizationContext类以及C#的Lambda表达式提供了一种方便的解决方法。以下是代码:
public static SynchronizationContext s_SC = Synchronization.Current; //主窗口类的静态成员
在App类中:
static volatile int s_nMainThreadID = Thread.CurrentThread.ManagedThreadId; //这个变量保存主线程ID(UI线程),为下面的属性服务,注意volatile修饰符,如果不用的话,在Release版本的程序可能会出错。
//这个属性表示当前执行线程是否在主线程中运行
public static bool IsRunInMainThread { get { return Thread.CurrentThread.ManagedThreadId == s_nMainThreadID;}}
//这个函数用于设置UI界面上的某个元素
public void SetText(string strText)
{
if (!App.IsRunInMainThread)
{
s_SC.Post(oo => { SetText(strText); }, null); //可以使用Post也可以使用Send
return;
}
textBlock1.Text = strText;
}
//这个函数用于从UI界面的元素获取内容
public string GetText()
{
if (!App.IsRunInMainThread)
{
string str = null;
s_SC.Send(oo => { str = GetText(); }, null); //必须要使用Send
return str;
}
return textBlock1.Text;
}
说明:虽然在主线程,也可以使用SynchronizationContext来更新界面,但那样做会导致性能大幅下降。例如以下两句语句的性能差距大约是15倍(假设都在主线程调用):
textBlock1.Text = "Hello"; //执行100万次用时1秒
s_SC.Send(oo => { textBlock1.Text = "Hello"; }, null); //执行100万次用时15秒
所以,每次执行界面更新函数时,判断是否在主线程执行是必要的。