WPF 文本 block 性能不佳

标签 wpf performance panel textblock

在显示少量数据时,我一直在使用 WPF DataGrid 和列表框 GridView 性能问题。我虽然这个问题只是 WPF 一般性能不佳,但问题似乎仅在于文本块控件。

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

看起来性能问题源于:

child.Measure(constraint); 

当文本块被测量时,它会使性能停滞不前。有什么我可以覆盖文本块的测量或提高性能的方法吗? (我会明确设置 child 的大小)

编辑:我现在已经创建了简化的代码来根据需要安排项目。

这段代码的性能很好,除了……当文本块内的文本宽度超过文本块的实际宽度时。这使我的表现回到了爬行状态 - 可能是因为它试图再次测量元素?
 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;

    }

最佳答案

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

话虽如此,您可能想尝试一些优化。测量通过的目标是确定您想要的尺寸。此外,您可以通过在所有子元素上调用 measure 来传播度量传递。但是,仅当您希望更改所需大小时才需要执行此操作。您似乎对具有 _rowHeight 和 _columnWidth 字段的布局了解很多。因此,请执行以下操作:

  • 使用以下方法测量您的 child :child.Measure(new Size(_columnWidth, _rowHeight)) .这是实际的约束吗?
  • 减少子元素的测量运行次数。通过将所有这些代码移出 MeasureOverride 并仅在 _rowHeight 或 _lineWidth 更改时才调用此函数(此外,这将是对子元素调用 Measure 的方法)。将这些字段实现为 DependencyProperties能够听取更改(如果您不喜欢 DependencyProperties,可以使用 INotifyPropertyChanged)
  • 最有可能的是,您可以在恒定时间(例如 numberOfColumns * _columnWidth...)
  • 内实现 MeasureOverride(现在无需测量您的子元素)
  • 为ArrangeOverride 实现类似的逻辑。
  • 换句话说:不要在 MeasureOverride/ArrangeOverride
  • 中做布局逻辑(即决定“这个元素是否适合这条线”之类的问题)

    但是,这种方法不考虑 TextBox 元素的所需大小。您可以不关心或单独解决此问题:
  • 聆听文本变化,选择适当的事件。
  • 如果 TextBox 中的文本发生更改,则仅为该特定文本框调用 Measure。 (您可以使用正无穷大作为约束来测量此文本框)
  • 调整您的 ColumnWidth 和 RowHeight 属性

  • 除了改进您的 MeasureOverride/ArrangeOverride 实现之外,您还可以为 TextBox 使用不同的(例如更轻量级的)ControlTemplate。我会选择重写 MeasureOverride/ArrangeOverride。

    关于WPF 文本 block 性能不佳,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6808642/

    相关文章:

    c# - VistaFolderBrowserDialog 未从正确的文件夹开始

    wpf - XBAP(通过网页的 WPF)死了吗?

    javascript - 如何在 JavaScript 中向对象添加函数而不会导致内存效率低下

    python - 如何创建一个 python 函数来计算面板数据的利差?

    java - 将对象添加到面板,而不需要重新开始?

    c# - RadPanelBarItem 中的垂直对齐文本和图像?

    wpf - 在 XAML 中设置 TextBox 的宽度,以便它能够显示 x 位

    c# - 我可以回到线程执行上下文吗?

    mysql - select ... where foo_id in (select id from ...) 效率

    performance - 如何加速java卡加密/解密(RSA)