定义: 有一个由字符串组成的二维数组(大约10列,1600行,长度固定为7个字符),作为WPF .NET 4.0网格控件的数据源。下面的代码片段用于填充显示来自数组值的标签的网格。注意:网格被添加到XAML并传递给函数PopulateGrid(参见Listing 1)。视觉输出实质上是一个表格化的数据表示,并处于只读模式(不需要双向绑定)。
问题: 性能是一个关键问题。使用强大的Intel-i3/8GB-DDR3 PC运行时,完成此操作需要令人难以置信的3...5秒;因此,IMHO,这个WPF网格性能至少比预期慢一个数量级,与例如常规WinForm数据感知控件或甚至Excel工作表中的类似控件/任务相比。
问题1: 如果有一种方法可以改进上述情况下的WPF网格的性能?请将您的答案/潜在改进指向下面提供的Listing 1和Listing 2中的代码片段。
问题1a: 提出的解决方案可能会实现对其他数据感知控件(例如DataGrid
到DataTable
)的数据绑定。我在Listing 2中添加了string[,]
到DataTable dt
转换器,以便其他控件的DataContext
(或ItemsSource
等)属性可以绑定到dt.DefaultView
。因此,在最简单的形式下,您能否提供一个简洁(理想情况下大约是几行代码,就像旧式数据感知控件那样)和有效(性能方面)的解决方案,实现WPF DataGrid
到 DataTable
对象的数据绑定?
非常感谢。
Listing 1. 用于从二维string[,]
值填充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:建议使用TextBlock
控件替换Label
控件,并使用其Text属性而非Content属性,这样可以加快执行速度,而且代码片段将与不包括Label
的Win 8中的VS 2012向前兼容。
注意 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>
Grid
是与布局相关的UI元素,与数据显示无关。我正在准备一个示例,使用动态定义列等内容的ItemsControl
。 - Federico Berasategui