如何在WPF中懒洋洋地创建UI元素?

我们正在创建一个大量使用高度装饰的输入元素的WPF应用程序。 装饰元素的一个简单示例是TextBox,它在没有焦点时看起来像只读TextBlock,并在接收焦点后变为TextBox。 另外,当更改的值被保存到数据库时会提供额外的视觉反馈。 问题是,显示一个包含很多这些元素的视图(比方说100)非常慢,并且使应用程序非常无响应。

我们已经实现了这个装饰器作为UserControl,它包含了所有必需的元素(例如TextBlock显示未聚焦的文本和忙图标的旋转图像)。 然后,我们将输入元素添加为此装饰器控件的子元素,这意味着除了所有额外的元素之外,装饰器还在其可视化树中包含输入元素。 在XAML中,这看起来像:

<custom:Decorator Context="{Binding ValueHelper}" >
    <TextBox Text="{Binding ValueHelper.Text}"/>
</custom:Decorator>

这使得我们可以很容易地装饰我们想要的任何输入元素,无论是文本框,日期选择器,组合框还是任何自定义元素。

现在回到问题 :假设我们有一个包含100个装饰文本框的视图,并导航到该视图。 怎么了? 至少我的四核笔记本电脑冻结了很长一段时间,因为它必须创建许多文本块,矩形,图像等,才能为每个装饰元素提供视觉反馈,尽管没有看到任何装饰。 真正需要的仅仅是100个TextBlocks,因为这是屏幕上可见的。 只有在元素接收到鼠标悬停事件后,或者在需要其他元素时才关注。 而且,一次只能编辑一个元素,因此只有一个输入元素(在这种情况下是文本框)对于整个应用程序就足够了。

那么,如果不为视图中的每个元素创建所有装饰元素(或实际输入元素),实现相同装饰的最佳方式是什么?


装饰TextBox的一个例子来阐明用例:

当文本框没有焦点时,文本框看起来像只读TextBlock,或者鼠标光标当前不在其上(状态1)。 此外,还显示了三个点(“...”),因为元素不会有任何价值。

当鼠标光标移动到元素顶部时,TextBlock周围会出现一个绿色的矩形框,表示该元素可以被修改(状态2)。 如果TextBox碰巧是只读的,颜色将会变成红色。

接收到焦点元素后,变成实际的文本框,可用于修改实际值(状态3)。

该值在文本框失去焦点后存储到数据库中,并且显示该值当前正在保存,一个繁忙指示符出现在元素的左侧(状态4)。

最后,该值已被保存,元素返回到显示新值的空闲状态(状态5)。 (其实这些元素有更多的状态与验证和其他特定要求有关,但您肯定知道元素真的是高度装饰。)


预先绘制所有的UI元素,而不是绘制所需的元素

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

Decorator的示例样式可能如下所示:

<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开始”的“ Collapsed ,并且只有在它们应该显示时才会设置为“ Visible

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

链接地址: http://www.djcxy.com/p/70261.html

上一篇: How to create UI elements lazily in WPF?

下一篇: ADFS session expires and causes error