我正在考虑将我的一个应用程序转换为WPF,我的主要关注点之一是DataGrid
控件的性能(我的用户的计算机是过时的没有专用图形的XP机器)。我尝试了几千行,滚动性能很糟糕。
我想知道是否有办法将datagrid单元格的内容设置为派生自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
,但性能仍然不佳。
答案 0 :(得分: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方法。
答案 1 :(得分:0)
确保DataGrid的EnableRowVirtualization属性设置为True。默认情况下它应该为True,但请确保它在某个样式中没有设置为False。
答案 2 :(得分:0)
UI Virtualization
。但它会在以下任一情况下被禁用 -
在度量排列过程中,DataGrid具有无限高度。 如果DataGrid认为它有足够的空间来排列所有项目,那么它将不会虚拟化任何内容。 当您将DataGrid放在堆栈面板中时,通常会发生这种情况。
datagrid的ItemsPanel。 虚拟化由VirtualizingStackPanel完成。如果更改ItemsPanel,则将删除VirtualizingStackPanel。
项目分组。 在.NET4.0中,虚拟化不支持分组。在某些情况下,将GroupStyle分配给DataGrid将关闭虚拟化,即使项目未分组也是如此。
请检查您是否属于上述任何情况。
作为旁注,您还可以在datagrid的Items Source上实现Data Virtualization
。可以在此处找到带有校样的样本 - Data Virtualization