Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>Here is a Control called <code>DataGrid2D</code> that can be populated based on a 2D or<br> 1D array (or anything that implements the <code>IList</code> interface). It subclasses <code>DataGrid</code> and adds a property called <code>ItemsSource2D</code> which is used for binding against 2D or 1D sources. Library can be downloaded <a href="http://www.mediafire.com/download.php?1bw6dm9y11fbmnu" rel="nofollow noreferrer">here</a> and source code can be downloaded <a href="http://www.mediafire.com/download.php?tm1arm230rr1tgi" rel="nofollow noreferrer">here</a>.</p> <p>To use it just add a reference to DataGrid2DLibrary.dll, add this namespace</p> <pre><code>xmlns:dg2d="clr-namespace:DataGrid2DLibrary;assembly=DataGrid2DLibrary" </code></pre> <p>and then create a DataGrid2D and bind it to your IList, 2D array or 1D array like this</p> <pre><code>&lt;dg2d:DataGrid2D Name="dataGrid2D" ItemsSource2D="{Binding Int2DList}"/&gt; </code></pre> <p><img src="https://i.stack.imgur.com/JL7xy.png" alt="enter image description here"></p> <hr> <p><strong>OLD POST</strong><br> Here is an implementation that can bind a 2D array to the WPF datagrid. </p> <p>Say we have this 2D array</p> <pre><code>private int[,] m_intArray = new int[5, 5]; ... for (int i = 0; i &lt; 5; i++) { for (int j = 0; j &lt; 5; j++) { m_intArray[i,j] = (i * 10 + j); } } </code></pre> <p>And then we want to bind this 2D array to the WPF DataGrid and the changes we make shall be reflected in the array. To do this I used Eric Lippert's Ref class from <a href="https://stackoverflow.com/questions/2980463/how-do-i-assign-by-reference-to-a-class-field-in-c/2982037#2982037">this</a> thread.</p> <pre><code>public class Ref&lt;T&gt; { private readonly Func&lt;T&gt; getter; private readonly Action&lt;T&gt; setter; public Ref(Func&lt;T&gt; getter, Action&lt;T&gt; setter) { this.getter = getter; this.setter = setter; } public T Value { get { return getter(); } set { setter(value); } } } </code></pre> <p>Then I made a static helper class with a method that could take a 2D array and return a DataView using the Ref class above.</p> <pre><code>public static DataView GetBindable2DArray&lt;T&gt;(T[,] array) { DataTable dataTable = new DataTable(); for (int i = 0; i &lt; array.GetLength(1); i++) { dataTable.Columns.Add(i.ToString(), typeof(Ref&lt;T&gt;)); } for (int i = 0; i &lt; array.GetLength(0); i++) { DataRow dataRow = dataTable.NewRow(); dataTable.Rows.Add(dataRow); } DataView dataView = new DataView(dataTable); for (int i = 0; i &lt; array.GetLength(0); i++) { for (int j = 0; j &lt; array.GetLength(1); j++) { int a = i; int b = j; Ref&lt;T&gt; refT = new Ref&lt;T&gt;(() =&gt; array[a, b], z =&gt; { array[a, b] = z; }); dataView[i][j] = refT; } } return dataView; } </code></pre> <p>This would almost be enough to bind to but the Path in the Binding will point to the Ref object instead of the Ref.Value which we need so we have to change this when the Columns get generated.</p> <pre><code>&lt;DataGrid Name="c_dataGrid" RowHeaderWidth="0" ColumnHeaderHeight="0" AutoGenerateColumns="True" AutoGeneratingColumn="c_dataGrid_AutoGeneratingColumn"/&gt; private void c_dataGrid_AutoGeneratingColumn(object sender, DataGridAutoGeneratingColumnEventArgs e) { DataGridTextColumn column = e.Column as DataGridTextColumn; Binding binding = column.Binding as Binding; binding.Path = new PropertyPath(binding.Path.Path + ".Value"); } </code></pre> <p>And after this we can use</p> <pre><code>c_dataGrid.ItemsSource = BindingHelper.GetBindable2DArray&lt;int&gt;(m_intArray); </code></pre> <p>And the output will look like this</p> <p><img src="https://i.stack.imgur.com/FvZro.png" alt="alt text"></p> <p>Any changes made in the <code>DataGrid</code> will be reflected in the m_intArray.</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload