2013-03-27 99 views
7

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

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

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

这很容易让我们来装点我们想要的任何输入元素,无论是任何一个文本框中,日期选择器,组合框或任何自定义元素。

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

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


装饰文本框,以澄清使用情况的一个例子:

文本框时像没有焦点或鼠标光标,只读TextBlock的目前并未在它的上面(状态1)。此外,还显示了三个点(“...”),因为元素不会有任何价值。

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

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

文本框失去它的焦点之后,并表明,该值正在被保存忙指示符显得元件(状态4)的左边的值存储到数据库中。

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

enter image description here

回答

4

除了绘制所有的UI元素前期的,只画出了那些需要

WPF允许你修改使用DataTrigger对象的Template,这样你就可以调整模板您根据您的触发器

装饰你的装饰一个例子风格可能会是这个样子:

<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时,他们应该显示。

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

+0

谢谢!控件模板绝对是装饰元素的方式。但是,这并不能解决实际输入元素的问题。 TextBox是我们最轻的元素,我们有更重的自定义输入元素(例如日期选择器),我们无法创建。我们已经设置了可见性来折叠,但仍然会创建可视化树,并加载所有相关资源,这会导致严重的性能问题。 – user544511 2013-03-28 08:04:43

+0

@ user544511当你说“所有相关资源被加载”时,你的意思是每个装饰器都被加载了吗?因为如果你使用的装饰一个UI控制和换出的模板,因为只有一个元素在视觉树同时 – Rachel 2013-03-28 11:52:10

+0

对不起,我正在度假,不能刚才的答复存在,你不应该让这种行为。我的意思是创建了实际的输入元素(这是装饰器的子元素,例如日期选取器或文本框),它的所有资源(包括子元素)都被加载并添加到可视树中(即使它已折叠)。这导致巨大的性能下降,因为日期选择器的元素比例如重量要大得多。一个文本框。 – user544511 2013-04-02 11:08:57