2011-07-24 41 views
4

我一直在WPF DataGrid和listbox GridView性能显示甚至少量的数据时遇到问题。我虽然这个问题只是WPF一般性能差,但问题似乎只在于文本块控制。WPF文本块性能差

我创建了一个样板,我添加了几个项目。如果我添加简单填充的矩形,调整大小/滚动性能是完美的,但是一旦我使用文本块,性能就会消失。

它看起来像性能问题来自:

child.Measure(constraint); 

当文本块被衡量的,它带来的性能嘎然而止。有什么我可以覆盖文本块的测量或某些东西来提高性能? (我会明确设置孩子的大小)

编辑:我现在已经创建了简化的代码来安排项目,因为我想。

这段代码的性能很好,除了......当textblock中文本的宽度超过文本块的实际宽度时。这使我的表现回落到了可能的原因 - 可能是因为它试图再次测量元素?

public class TestPanel : Panel 
{ 
    private int _rowHeight = 20; 
    private int _columnWidth = 50; 

    public TestPanel() 
    { 

     for (int i = 0; i < 100; i++) 
     { 

      for (int j = 0; j < 20; j++) 
      { 
       TextBlock cell = new TextBlock(); 
       cell.ClipToBounds = true; 
       cell.Width = _columnWidth; 
       cell.Height = _rowHeight; 
       cell.Text = i.ToString() + ":" + j.ToString(); 
       this.Children.Add(cell); 
      } 
     } 
    } 

    protected override Size MeasureOverride(Size constraint) 
    { 
     return new Size(_columnWidth*20,_rowHeight*100); 
    } 

    protected override Size ArrangeOverride(Size arrangeBounds) 
    { 
     UIElementCollection children = InternalChildren; 

     for (int i = 0; i < 100; i++) 
     { 
      for (int j = 0; j < 20; j++) 
      { 
       UIElement child = children[i*20+j]; 
       child.Arrange(new Rect(j * _columnWidth, i * 20, _columnWidth, 20)); 
      } 
     } 
     return arrangeBounds; 
    } 
} 

public MainWindow() 
    { 
     InitializeComponent(); 

     TestPanel myPanel = new TestPanel(); 
     ScrollViewer scroll = new ScrollViewer(); 

     myPanel.Background = Brushes.Aqua; 

     scroll.Content = myPanel; 
     this.Content = scroll; 

    } 

回答

5

TextBox和Rectangle之间的性能差异是由于这些控件的复杂性不同。只需比较分辨视觉树(即使用XamlPad)的复杂性即可。一个矩形很可能只是知道它想要的尺寸。另一方面,一个文本框在计算所需大小时需要考虑许多不同的因素,例如所需大小的文本(我猜这是真正的瓶颈)。

说了这么多,你可能想尝试一些优化。度量通过的目标是确定您所需的大小。此外,您通过调用所有子元素上的度量来传播度量传递。但是,如果您希望更改所需大小,则只需执行此操作。看起来你知道很多有关_rowHeight和_columnWidth字段的布局。所以做到以下几点:

  • 测量你的孩子使用:child.Measure(new Size(_columnWidth, _rowHeight))。这是实际的限制吗?
  • 减少您的子元素的度量运行次数。通过将所有代码移出MeasureOverride并仅在_rowHeight或_lineWidth更改时调用此函数(同时,这将是您的子元素上调用Measure的方法)来完成此操作。实现这些字段为DependencyProperties以便能够监听更改(如果您不喜欢DependencyProperties,则可以使用INotifyPropertyChanged
  • 最有可能的是,您可以在常量时间内实现MeasureOverride(现在不必测量您的子元素)(例如numberOfColumns * _columnWidth...
  • 为ArrangeOverride实现类似的逻辑。
  • 换句话说:不做布局逻辑(即决定象“此元件配合到这一行”的问题)在的MeasureOverride/ArrangeOverride

这种方法,然而,不尊重的所需尺寸TextBox元素。你可以不关心或分开解决:

  • 听文本更改,选择适当的事件。
  • 如果文本框中的文本发生更改,请仅为此特定文本框调用“度量值”。 (你可以测量这个文本框与正无穷大的约束)
  • 适应您columnWidth中和rowHeight属性

除了提高你的MeasureOverride/ArrangeOverride实现您可以使用不同的(例如更轻巧)的ControlTemplate对TextBox。我会选择重写MeasureOverride/ArrangeOverride。

+0

看来,即使我覆盖布局面板的度量替代,当文本长于块时,也会出现一个度量。有没有什么好方法可以防止这种情况发生? – ChandlerPelhams

3

首先,在测试代码之后,您似乎已经重写了WPF中已存在的WrapPanel。当我将TestPanel替换为WrapPanel时,行为完全相同,性能有所提高。

其次,我想知道什么样的硬件,特别是您使用的视频卡。当我在PC上运行这个示例时,我几乎没有看到任何滞后。当然不是你正在谈论的“打磨停顿”。

最后,我所知道的改进文本渲染性能的唯一方法是使用低级文本对象。想起了FormattedText。然而,这与TextBlock相比要困难得多,所以我鼓励你在转换到FormattedText之前考虑你想要完成的是什么。

编辑

其中WPF是伤害你的表现真正的区域是在测量和安排layout系统的通行证。理解每次调整窗口大小都很重要,WPF正在重新计算每个用户界面元素的大小和位置,然后相应地重新排列它们。这对于实现灵活的布局或创建动态用户界面非常有用,但是对于静态数据网格(这似乎是您的想法),这样做会带来更多的负面影响。在大多数机器上,WPF将尽可能多的工作分配给GPU。然而,在你的情况下,CPU正在处理所有事情,因此你在调整大小时看到的“流失”。

FormattedText会更快,但不适合使用数据网格。与其编写自己的布局面板(WPF中1%的场景),我会切换到ListView或第三方网格组件,并查看当时性能如何。这些类型的组件被构建(并优化)以显示大量不断变化的数据 - WPF布局面板被构建为包含其他用户界面元素和绘图。

+0

好吧,我目前在我的笔记本电脑上安装了T4200(2.00 Ghz双核),带有2个内存和板载显卡 - 这是我工作时计算机上的一个步骤,它可以运行这个 - 〜3GHz学校奔腾4 W /没有专用显卡。我知道我重新编写了包装面板 - 我的最终目标是创建一个数据网格,但我现在只想测试面板...您认为FormattedText会比TextBlock快得多吗? – ChandlerPelhams

+0

查看我上面的编辑。 – Charlie

+0

感谢您的额外输入。我以前曾尝试使用listview,与标准数据网格相比,性能提升最小,此时不可能使用第三方控件。我对编写自定义面板还是比较陌生 - 是否有一种简单的方法来编写排列和度量过程,以便不必执行复杂的计算,如果我知道每个cild的大小,确切地说每行有多少个子节点,会有? – ChandlerPelhams