我在WPF客户端应用上运行了一个非常简单的性能测试:
public partial class MainWindow : Window
{
private ObservableCollection<int> data = new ObservableCollection<int>();
public ObservableCollection<int> DataObj { get { return data; } }
private void button1_Click(object sender, RoutedEventArgs e)
{
for (int j = 0; j < 5; j++)
{
Thread t = new Thread(() =>
{
for (int i = 0; i < 100; i++)
{
Thread.Sleep(5);
Dispatcher.Invoke(new Action(() => { data.Add(1); })); //updates the count
Dispatcher.Invoke(new Action(() => { richTextBox1.AppendText("1"); })); //updates the string data
}
});
t.Start();
}
}
然后我在UI中有两个控件:TextBlock
和RichTextBox
。
TextBlock
绑定到数据源的Count
属性,而RichTextBox
将每个新数据值附加到其文本字符串(即显示数据内容)。
如果我禁用RichTextBox
绑定,TextBlock
会很快更新,循环计数。但是,启用RichTextBox
绑定会降低所有内容,两者都会控制“globs”中的更新,可能每秒一次或两次。换句话说,整个UI以RichTextBox
绑定的速度运行。
有没有办法打破这种性能依赖?我理解RichTextBox可能会很慢,但为什么它必须减慢快速的快速TextBlock?
答案 0 :(得分:6)
WPF的特定之处在于每个窗口只有一个UI线程。
虽然可以使用其他窗口并使其看起来好像是当前应用程序的一部分(将WindowStyle属性设置为None并更新位置和大小),但它看起来并不自然,并且有更好的方法解决性能问题。
众所周知,有必要使用Dispatcher
类从后台线程更新UI。 BeginInvoke
方法具有DispatcherPriority类型的可选参数,其具有以下值。
默认值为Normal (9)
,它几乎是最高优先级,只要您调用不带参数的BeginInvoke
方法,就会隐式应用它。在您的示例中对RichTextBox
的调用具有此优先级。
但是绑定到该属性并且未手动更新的TextBlock
优先级较低DataBind (8)
,这就是更新速度较慢的原因。
为了更快地进行绑定,您可以降低对RichTextBox
的调用的优先级,并设置低于8的值,例如Render (7)
。
Dispatcher.Invoke(/*...*/, DispatcherPriority.Render);
它有助于绑定,但UI不会响应鼠标点击,你甚至无法关闭窗口。
继续降低优先级:
Dispatcher.Invoke(/*...*/, DispatcherPriority.Input);
应用程序响应更好,但在文本填充时RichTextBox
仍然无法输入内容。
因此最终值为Background (4)
:
Dispatcher.Invoke(new Action(() => { richTextBox1.AppendText("1"); }),
DispatcherPriority.Background);