0

我正在考虑将我的一个应用程序转换为 WPF,我主要关心的问题之一是DataGrid控件的性能(我用户的计算机是过时的 XP 机器,没有专用图形)。我尝试了几千行,滚动性能很糟糕。

我想知道是否有办法将数据网格单元格的内容设置为派生自的自定义类FrameworkElement

这是一个示例类,当放入虚拟化堆栈面板时,它的性能似乎要好得多:

public class LiteTextBlock : FrameworkElement
{
    private Size _mySize;
    private string _myText;
    private double totalWidth;
    private GlyphTypeface _typeface;
    private int _fontSize;
    private GlyphRun _run;

    public LiteTextBlock(Size mySize, string myText, GlyphTypeface typeface, int fontSize)
    {
        _mySize = mySize;
        this.Width = _mySize.Width;
        this.Height = _mySize.Height;
        _myText = myText + " additional information";
        _typeface = typeface;
        _fontSize = fontSize;
    }

    protected override void OnRender(DrawingContext drawingContext)
    {
        if (_run == null)
        {
            totalWidth = 0;

            ushort[] glyphIndexes = new ushort[_myText.Length];
            double[] advanceWidths = new double[_myText.Length];

            for (int i = 0; i < _myText.Length; i++)
            {
                ushort glyphIndex = _typeface.CharacterToGlyphMap[_myText[i]];
                double width = _typeface.AdvanceWidths[glyphIndex] * _fontSize;

                if (totalWidth + width >= _mySize.Width - 10)
                {
                    Array.Resize(ref glyphIndexes, i);
                    Array.Resize(ref advanceWidths, i);
                    break;
                }

                glyphIndexes[i] = glyphIndex;
                advanceWidths[i] = width;
                totalWidth += width;
            }

            Point origin = new Point(5, 0);

            _run = new GlyphRun(_typeface, 0, false, _fontSize, glyphIndexes
                , origin, advanceWidths, null, null, null, null, null, null);
        }

        drawingContext.DrawGlyphRun(Brushes.Black, _run);
    }
}

谁能告诉我这是否可能?

免责声明:我已经尝试过使用轻量级控件,例如ListView,但性能仍然很差。

4

3 回答 3

1

是的,有办法。

您需要实现自定义DataGridColumn并覆盖其GenerateElement方法,并且需要处理DataGrid.AutoGeneratingColumn事件以将自定义 DataGridColumn 设置为 DataGrid。

这是自定义 DataGridColumn 的示例:

public class DataGridLiteTextColumn : DataGridColumn
{
    private readonly PropertyDescriptor property;

    private readonly GlyphTypeface glyphTypeface = new GlyphTypeface(new Uri("file:///C:\\WINDOWS\\Fonts\\Arial.ttf"));

    public DataGridLiteTextColumn(PropertyDescriptor property)
    {
        this.property = property;
    }

    protected override FrameworkElement GenerateElement(DataGridCell cell, object dataItem)
    {
        var value = property.GetValue(dataItem);
        return new LiteTextBlock(new Size(100, 20), value != null ? value.ToString() : string.Empty, this.glyphTypeface, 10);
    }

    protected override FrameworkElement GenerateEditingElement(DataGridCell cell, object dataItem)
    {
        throw new NotImplementedException();
    }
}

这是 DataGrid.AutoGeneratingColumn 事件的处理程序:

private void OnAutoGeneratingColumn(object sender, DataGridAutoGeneratingColumnEventArgs e)
{
    e.Column = new DataGridLiteTextColumn((PropertyDescriptor)e.PropertyDescriptor);
}

此代码将用于显示值,尽管 LiteTextBlock 构造函数大小参数可能未设置为适当的值。要编辑值,您还必须实现GenerateEditingElement方法。

于 2012-10-01T19:19:55.760 回答
0

UI Virtualization默认启用。但在以下任何一种情况下它都会被禁用 -

  1. DataGrid 在测量排列过程中具有无限的高度。如果 DataGrid 认为它有足够的空间来排列所有项目,那么它不会虚拟化任何东西。当您将 DataGrid 放在堆栈面板中时,通常会发生这种情况。

  2. 数据网格的 ItemsPanel。虚拟化由 VirtualizingStackPanel 完成。如果您更改 ItemsPanel,则 VirtualizingStackPanel 将被删除。

  3. 项目分组。在 .NET4.0 中,虚拟化不支持分组。在某些情况下,将 GroupStyle 分配给 DataGrid 将关闭虚拟化,即使项目未分组。

请检查您没有陷入上述任何情况。

作为旁注,您还可以Data Virtualization在数据网格的 Items Source 上实现。可以在此处找到具有相同证明的示例 -数据虚拟化

于 2012-10-01T17:41:41.997 回答
0

确保 DataGrid 的EnableRowVirtualization属性设置为 True。默认情况下它应该是 True,但请确保它没有在某处的 Style 中设置为 False。

于 2012-10-01T14:41:55.153 回答