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