如何将 2D 数组绑定到 WPF 中的 ListView?
将 2D 数组绑定到 WPF ListView 的 2 种解决方案

引言
WPF 绑定非常有用且强大。您可以将任何内容绑定到 ItemsControl.ItemsSource
,该控件继承自 IEnumerable
接口,例如一维数组、List<T>
、Collection<T>
等。但它无法绑定二维数组。如果您绑定多维数组(例如二维数组),则会显示异常“数组不是一维数组”。
解决方案 1:转换为继承自 IEnumerable 接口的类,例如 DataTable,然后将其绑定到 ListView
许多类都继承自 IEnumerable
,例如 List<T>
、Collection<T>
、Dictionary<Key, Value>
等。在此解决方案中,我计划将其转换为 DataTable
以供通用使用。
首先准备一个二维数组,我们生成了一个 100000 * 6 的二维数组。
double[,] data = new double[100000, 6];
for (int i = 0; i < data.GetLength(0); i++)
{
data[i, 0] = i + 1;
for (int j = 1; j < data.GetLength(1); j++)
{
data[i, j] = j + 1;
}
}
我们将此数组转换为 DataTable
,DataTable
的列数应等于数组的第二个维度长度,在本示例中为 6。
private DataTable Convert2DArrayToDataTable(double[,] data, string[] columnNames)
{
int len1d = data.GetLength(0);
int len2d = data.GetLength(1);
Check2DArrayMatchColumnNames(data, columnNames);
DataTable dt = new DataTable();
for (int i = 0; i < len2d; i++)
{
dt.Columns.Add(columnNames[i], typeof(double));
}
for (int row = 0; row < len1d; row++)
{
DataRow dr = dt.NewRow();
for (int col = 0; col < len2d; col++)
{
dr[col] = data[row, col];
}
dt.Rows.Add(dr);
}
return dt;
}
private void Check2DArrayMatchColumnNames(double[,] data, string[] columnNames)
{
int len2d = data.GetLength(1);
if (len2d != columnNames.Length)
{
throw new Exception("The second dimensional length must equals column names.");
}
}
列名是什么?我们将其用作 DataTable
中的字段名。在调试时,这很有用,您可以在 DataView
中查看 DataTable
。接下来,我们初始化 ListView
视图和列。
private void Binding2DArrayToListView
(ListView listview, double[,] data, string[] columnNames)
{
Check2DArrayMatchColumnNames(data, columnNames);
DataTable dt = Convert2DArrayToDataTable(data, columnNames);
GridView gv = new GridView();
for (int i = 0; i < data.GetLength(1); i++)
{
GridViewColumn col = new GridViewColumn();
col.Header = columnNames[i];
col.DisplayMemberBinding = new Binding("[" + i + "]");
gv.Columns.Add(col);
}
lvwArray.View = gv;
lvwArray.ItemsSource = dt.Rows;
}
现在完成了。但是,这种需要转换的解决方案存在性能问题。如果数组较大,则转换将需要很长时间。无论转换为任何类型。更好的解决方案是什么?请继续阅读解决方案 2。
解决方案 2:编写数组访问器,然后将其绑定到 ListView
解决方案 1 和解决方案 2 之间的最大区别在于,解决方案 1 需要转换过程。但解决方案 2 不需要。我们编写一个数组访问器来访问数组。以下是代码
class ArrayVisitor : IEnumerable<double[]>
{
private double[,] _data;
public ArrayVisitor()
{
}
public ArrayVisitor(double[,] data)
{
_data = data;
}
public double[,] Data
{
get { return _data; }
set { _data = value; }
}
#region IEnumerable<double[]> Members
public IEnumerator<double[]> GetEnumerator()
{
if (_data == null)
throw new ArgumentException("Data cannot be null.", "Data");
int len2d = _data.GetLength(1);
for (int i = 0; i < _data.GetLength(0); i++)
{
double[] arr = new double[len2d];
for (int j = 0; j < len2d; j++)
{
arr[j] = _data[i, j];
}
yield return arr;
}
}
#endregion
#region IEnumerable Members
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
#endregion
}
如何在代码中使用它?
private void Bindng2DArrayToListview2
(ListView listview, double[,] data, string[] columnNames)
{
Check2DArrayMatchColumnNames(data, columnNames);
GridView gv = new GridView();
for (int i = 0; i < data.GetLength(1); i++)
{
GridViewColumn col = new GridViewColumn();
col.Header = columnNames[i];
col.DisplayMemberBinding = new Binding("[" + i + "]");
gv.Columns.Add(col);
}
ArrayVisitor arrayVisitor = new ArrayVisitor(data);
listview.View = gv;
listview.ItemsSource = arrayVisitor;
}
享受代码吧!
历史
- 2010年3月19日:初始发布