【发布时间】:2013-05-15 14:04:19
【问题描述】:
定义:将二维字符串数组(约10列,1600行,固定长度7个字符)作为WPF .NET 4.0 Grid控件的数据源,如下代码sn -p 已用于使用显示数组值的标签填充网格。 注意:Grid 已添加到 XAML 并传递给函数 PopulateGrid(参见清单 1)。视觉输出本质上是只读模式下的表格数据表示(无需双向绑定)。
问题:性能是一个关键问题。在功能强大的 Intel-i3/8GB-DDR3 PC 上运行此操作需要令人难以置信的 3...5 秒;因此,恕我直言,此 WPF Grid 性能至少比预期慢一个数量级,基于与类似控件/任务的比较,例如常规的 WinForm 数据感知控件,甚至 Excel 工作表。
问题 1:在上述场景中是否有办法提高 WPF Grid 的性能?请将您的答案/潜在改进指向下面清单 1 和清单 2 中提供的代码 sn-p。
问题 1a:建议的解决方案可以将数据绑定到额外的数据感知控件,例如 DataGrid 到 DataTable。我已在清单 2 中将 string[,] 添加到 DataTable dt 转换器,以便附加控件的 DataContext(或 ItemsSource,等等)属性可以绑定到 dt.DefaultView。因此,以最简单的形式,您能否提供一个紧凑的(最好是几行代码,因为它是在旧式数据感知控件中完成的)和高效(性能方面)的 WPF 数据绑定解决方案DataGrid 到 DataTable 对象 ?
非常感谢。
清单 1。从 2D string[,] Values 填充 WPF Grid GridOut 的过程
#region Populate grid with 2D-array values
/// <summary>
/// Populate grid with 2D-array values
/// </summary>
/// <param name="Values">string[,]</param>
/// <param name="GridOut">Grid</param>
private void PopulateGrid(string[,] Values, Grid GridOut)
{
try
{
#region clear grid, then add ColumnDefinitions/RowsDefinitions
GridOut.Children.Clear();
GridOut.ColumnDefinitions.Clear();
GridOut.RowDefinitions.Clear();
// get column num
int _columns = Values.GetUpperBound(1) + 1;
// add ColumnDefinitions
for (int i = 0; i < _columns; i++)
{
GridOut.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(1, GridUnitType.Star) });
}
// get rows num
int _rows = Values.GetUpperBound(0) + 1;
// add RowDefinitions
for (int i = 0; i < _rows; i++)
{
GridOut.RowDefinitions.Add(new RowDefinition { Height = new GridLength(1, GridUnitType.Star) });
}
#endregion
#region populate grid w/labels
// populate grid w/labels
for (int i = 0; i < _rows; i++)
{
for (int j = 0; j < _columns; j++)
{
// new Label control
Label _lblValue = new Label();
// assign value to Label
_lblValue.Content = Values[i, j].ToString();
// add Label to GRid
GridOut.Children.Add(_lblValue);
Grid.SetRow(_lblValue, i);
Grid.SetColumn(_lblValue, j);
}
}
#endregion
}
catch
{
GridOut.Children.Clear();
GridOut.ColumnDefinitions.Clear();
GridOut.RowDefinitions.Clear();
}
}
#endregion
清单 2。 string[,] 到 DataTable 转换
#region internal: Convert string[,] to DataTable
/// <summary>
/// Convert string[,] to DataTable
/// </summary>
/// <param name="arrString">string[,]</param>
/// <returns>DataTable</returns>
internal static DataTable Array2DataTable(string[,] arrString)
{
DataTable _dt = new DataTable();
try
{
// get column num
int _columns = arrString.GetUpperBound(1) + 1;
// get rows num
int _rows = arrString.GetUpperBound(0) + 1;
// add columns to DataTable
for (int i = 0; i < _columns; i++)
{
_dt.Columns.Add(i.ToString(), typeof(string));
}
// add rows to DataTable
for (int i = 0; i < _rows; i++)
{
DataRow _dr = _dt.NewRow();
for (int j = 0; j < _columns; j++)
{
_dr[j] = arrString[i,j];
}
_dt.Rows.Add(_dr);
}
return _dt;
}
catch { throw; }
}
#endregion
注意 2。建议使用其 Text 属性而不是 Content 替换 Label 控件 w/TextBlock,就像 Label 的情况一样。它将稍微加快执行速度,而且代码 sn-p 将与 VS 2012 for Win 8 前向兼容,其中不包括 Label。
注意 3:到目前为止,我已经尝试将 DataGrid 绑定到 DataTable(参见清单 3 中的 XAML),但性能很差(grdOut 是嵌套的 Grid ,用作表格数据的容器;_dataGrid 是 DataGrid 的数据感知对象类型。
清单 3。 DataGrid 绑定到 DataTable:性能很差,所以我删除了 ScrollViewer,但它运行不正常。
<ScrollViewer ScrollViewer.CanContentScroll="True" VerticalScrollBarVisibility="Auto" >
<Grid Name="grdOut">
<DataGrid AutoGenerateColumns="True" Name="_dataGrid" ItemsSource="{Binding Path=.}" />
</Grid>
</ScrollViewer>
【问题讨论】:
-
您没有性能问题。你有一个设计问题。你绝对不应该在 WPF 中这样做。使用具有内置 UI 虚拟化的
ItemsControl。发布您需要的屏幕截图,我可以告诉您在 WPF 中执行此操作的正确方法。请忘记 winforms 的心态。 -
@HighCore:感谢您的回复。我非常了解还有许多其他方法可以通过其他控件来实现此功能,例如ListView 或 DataGrid 等。在我的问题中明确指出,我正在寻找与 Grid 控件使用相关的解决方案。仅当发现与 WPF Grid 相关的所有其他选项都不足时,我才会考虑涉及任何其他控件的解决方案。最好的问候,
-
同样,
Grid是与Layout相关的 UI 元素。我与显示数据无关。我正在准备一个使用ItemsControl和动态定义的列和内容的示例。 -
@HighCore:再次感谢。作为仅供参考,我已经看到了很多关于其他 WPF 数据感知控件(如 ListView 或 DataGrid)性能的关键 cmets,关键问题是实现 UI 虚拟化,这(可能)提供了巨大的性能提升。如果这确实是一个关键点,那么请详细说明它提供详细的解决方案,或者只是链接到现有的解决方案。问候,
标签: wpf wpf-controls wpfdatagrid wpf-4.0 wpf-4.5