通过将UI分解为';地区';-这可能吗
本文关键字:地区 分解 UI | 更新日期: 2023-09-27 17:49:38
我在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?
WPF的特殊之处在于每个窗口只有一个UI线程。
尽管可以使用其他窗口并使其看起来像是当前应用程序的一部分(将WindowStyle属性设置为None并更新位置和大小(,但它看起来并不自然,而且有更好的方法来解决性能问题。
众所周知,有必要使用Dispatcher
类从后台线程更新UI。BeginInvoke
方法具有DispatcherPriority类型的可选参数,该参数具有以下值。
- 系统空闲
- 应用程序空闲
- 上下文空闲
- 背景
- 输入
- 已加载
- 渲染
- 数据绑定
- 正常
- 发送
默认值是Normal (9)
,它几乎是最高优先级,并且无论何时调用不带参数的BeginInvoke
方法都会隐式应用它。在您的示例中,对RichTextBox
的调用具有此优先级。
但是绑定到属性并且不手动更新的TextBlock
具有较低的优先级DataBind (8)
,这就是它更新较慢的原因。
为了使绑定更快,可以降低对RichTextBox
的调用的优先级,并设置一个低于8的值,例如Render (7)
。
Dispatcher.Invoke(/*...*/, DispatcherPriority.Render);
它将有助于绑定,但用户界面不会对鼠标单击做出响应,您甚至无法关闭窗口。
继续降低优先级:
Dispatcher.Invoke(/*...*/, DispatcherPriority.Input);
应用程序的响应更好,但在由文本填充的RichTextBox
中仍然无法键入内容。
因此,最终值为Background (4)
:
Dispatcher.Invoke(new Action(() => { richTextBox1.AppendText("1"); }),
DispatcherPriority.Background);