我们正在创建一个 WPF 应用程序,它大量使用高度修饰的输入元素。装饰元素的一个简单示例是一个 TextBox,它在没有焦点时看起来像一个只读的 TextBlock,并在获得焦点后变成一个 TextBox。此外,在将更改的值保存到数据库时会提供额外的视觉反馈。问题是显示包含大量这些元素(比如说 100 个)的视图非常慢,并且使应用程序非常无响应。
我们已经将此装饰器实现为包含所有必需元素的 UserControl(例如用于显示未聚焦文本和忙碌指示器的旋转图像的 TextBlock)。然后我们将输入元素添加为这个装饰器控件的子元素,这意味着除了所有额外的元素之外,装饰器还包含其可视树中的输入元素。在 XAML 中,这看起来像:
<custom:Decorator Context="{Binding ValueHelper}" >
<TextBox Text="{Binding ValueHelper.Text}"/>
</custom:Decorator>
这使我们可以轻松地装饰我们想要的任何输入元素,无论是文本框、日期选择器、组合框还是任何自定义元素。
现在回到问题:假设我们有一个包含 100 个装饰文本框的视图,我们导航到该视图。怎么了?至少我的四核笔记本电脑冻结了很长时间,因为它必须创建数百个文本块、矩形、图像等来为每个装饰元素提供视觉反馈,尽管还没有可见的装饰。真正需要的只是 100 个文本块,因为这是屏幕上可见的内容。只有在元素接收到鼠标悬停事件或焦点后,才需要其他元素。此外,一次只编辑一个元素,因此对于整个应用程序来说,只有一个输入元素(在本例中为文本框)就足够了。
那么,在不为视图中的每个元素创建所有装饰元素(或实际输入元素)的情况下实现相同装饰的最佳方法是什么?
用于阐明用例的装饰文本框示例:
当文本框没有焦点或鼠标光标当前不在其顶部时(状态 1),该文本框看起来像一个只读 TextBlock。此外,显示了三个点(“...”),因为元素当前没有任何值。
当鼠标光标移动到元素顶部时,TextBlock 周围会出现一个绿色虚线矩形,表示可以修改该元素(状态 2)。如果 TextBox 碰巧是只读的,则颜色将为红色。
接收到焦点元素后变成实际的TextBox,可以用来修改实际值(状态3)。
在文本框失去焦点后,该值被存储到数据库中,并且为了显示该值当前正在保存,一个忙碌指示符出现在元素的左侧(状态 4)。
最后,该值已被保存,元素返回到显示新值的空闲状态(状态 5)。(实际上,元素具有与验证和其他特定要求相关的更多状态,但您肯定明白元素确实是高度修饰的。)