Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

How to Bind 2D Array to Listview in WPF?

0.00/5 (No votes)
19 Mar 2010 1  
2 solutions how to bind 2 array ListView in WPF
binding_2d_array_listview.png

Introduction

WPF binding is useful and powerful. You can bind anything to ItemsControl.ItemsSource which inherited from IEnumerable interface, like one dimension array, List<T>, Collection<T>, and so on. But it can bind a 2D array. An exception "Array was not a one-dimensional array" is shown if you bind a multi-dimension array, like 2D array. 

Solution 1: Convert to a Class which Inherited from IEnumerable Interface, like DataTable, then Bind it to ListView

Many classes are inherited from IEnumerable, like List<T>, Collection<T>, Dictionary<Key, Value> and so on. In this solution, I plan to convert it to DataTable for general use. 

Prepare a 2D array first, we generated a 2d array with 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;
    }
}

We convert this array to a DataTable, the columns count of DataTable should equal to the 2nd dimension length of array, in this sample, it was 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.");
    }
}

What are the columnNames? We used it as field names in DataTable. It's useful when you are debugging, you can view the DataTable in DataView. Next, we initialized the ListView view and columns. 

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;
}

Now, it's done. But this kind of solution which needs conversion has a performance issue. Conversion will take a long time if the array is a larger one. Whatever converts to any type. What's the better solution? Please continue to solution 2.

Solution 2: Write an Array Visitor, then Bind it to ListView

The most difference between solution 1 and solution 2 are, the solution needs a process conversion. But solution 2 does not need it. We write an array visitor to visit array. Here comes the code:

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
}

How to use it in code?

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;
}

Enjoy the code!

History

  • 19th March, 2010: Initial post

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here