7

我们正在创建一个 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)。(实际上,元素具有与验证和其他特定要求相关的更多状态,但您肯定明白元素确实是高度修饰的。)

在此处输入图像描述

4

1 回答 1

4

无需预先绘制所有 UI 元素,只绘制需要的元素

WPF 允许您使用 修改Template对象的DataTrigger,因此您可以根据触发器调整装饰器的模板

装饰器的示例样式可能如下所示:

<Style TargetType="{x:Type ContentControl}">
    <!-- Default Template -->
    <Setter Property="ContentTemplate" 
            Value="{StaticResource NoDecoratorTemplate}" />

    <Style.Triggers>
        <DataTrigger Property="Text" Value="">
            <Setter Property="ContentTemplate" 
                    Value="{StaticResource BlankTemplate}" />
        </DataTrigger>
        <Trigger Property="IsMouseOver" Value="True">
            <Setter Property="ContentTemplate" 
                    Value="{StaticResource MouseOverTemplate}" />
        </Trigger>
        <Trigger Property="IsFocused" Value="True">
            <Setter Property="ContentTemplate" 
                    Value="{StaticResource FocusedTemplate}" />
        </Trigger>
        <DataTrigger Property="{Binding IsLoading}" Value="True">
            <Setter Property="ContentTemplate" 
                    Value="{StaticResource LoadingTemplate}" />
        </DataTrigger>
    </Style.Triggers>
</Style>

此外,WPF 不应加载不可见的项目。您可以尝试将您的装饰器设置Visibility="Collapsed"为测试,以查看是否可以修复加载时间。

如果确实如此,并且您不想走这Template条路线,则可以确保将Visibility所有对象的 设置为Collapsed开始,并且仅将Visible它们设置为应该显示的时间。

如果它不能解决您的加载时间,那么您的问题可能出在其他地方。例如,看起来你的一些装饰器项目的大小是根据放置在其中的内容控件来调整的,所以实际上让你放慢速度的可能不是显示对象,而是确定对象的大小。

于 2013-03-27T13:25:04.033 回答