.net - mostrar - llenar una columna de un datagridview c#
Cómo llenar una grilla WPF basada en una matriz bidimensional (5)
Tengo una matriz bidimensional de objetos y, básicamente, quiero conectarlos en una celda en una grilla WPF. Actualmente tengo esto funcionando pero estoy haciendo la mayor parte del proceso. Creo el número correcto de definiciones de filas y columnas, luego recorro las celdas y creo los controles y configuro los enlaces correctos para cada uno.
Como mínimo, me gustaría poder utilizar una plantilla para especificar los controles y enlaces en xaml. Idealmente, me gustaría deshacerme del código de procedimiento y simplemente hacerlo todo con enlaces de datos, pero no estoy seguro de que eso sea posible.
Aquí está el código que estoy usando actualmente:
public void BindGrid()
{
m_Grid.Children.Clear();
m_Grid.ColumnDefinitions.Clear();
m_Grid.RowDefinitions.Clear();
for (int x = 0; x < MefGrid.Width; x++)
{
m_Grid.ColumnDefinitions.Add(new ColumnDefinition() { Width = new GridLength(1, GridUnitType.Star), });
}
for (int y = 0; y < MefGrid.Height; y++)
{
m_Grid.RowDefinitions.Add(new RowDefinition() { Height = new GridLength(1, GridUnitType.Star), });
}
for (int x = 0; x < MefGrid.Width; x++)
{
for (int y = 0; y < MefGrid.Height; y++)
{
Cell cell = (Cell)MefGrid[x, y];
SolidColorBrush brush = new SolidColorBrush();
var binding = new Binding("On");
binding.Converter = new BoolColorConverter();
binding.Mode = BindingMode.OneWay;
BindingOperations.SetBinding(brush, SolidColorBrush.ColorProperty, binding);
var rect = new Rectangle();
rect.DataContext = cell;
rect.Fill = brush;
rect.SetValue(Grid.RowProperty, y);
rect.SetValue(Grid.ColumnProperty, x);
m_Grid.Children.Add(rect);
}
}
}
Aquí hay otra solución basada en la respuesta de Meleak pero sin requerir un manejador de eventos AutoGeneratingColumn
en el código detrás de cada DataGrid
enlazado:
public static DataView GetBindable2DArray<T>(T[,] array)
{
var table = new DataTable();
for (var i = 0; i < array.GetLength(1); i++)
{
table.Columns.Add(i+1, typeof(bool))
.ExtendedProperties.Add("idx", i); // Save original column index
}
for (var i = 0; i < array.GetLength(0); i++)
{
table.Rows.Add(table.NewRow());
}
var view = new DataView(table);
for (var ri = 0; ri < array.GetLength(0); ri++)
{
for (var ci = 0; ci < array.GetLength(1); ci++)
{
view[ri][ci] = array[ri, ci];
}
}
// Avoids writing an ''AutogeneratingColumn'' handler
table.ColumnChanged += (s, e) =>
{
var ci = (int)e.Column.ExtendedProperties["idx"]; // Retrieve original column index
var ri = e.Row.Table.Rows.IndexOf(e.Row); // Retrieve row index
array[ri, ci] = (T)view[ri][ci];
};
return view;
}
Aquí hay un Control llamado DataGrid2D
que puede ser poblado basado en un 2D o
Matriz 1D (o cualquier cosa que implemente la interfaz IList
). ItemsSource2D
DataGrid
y agrega una propiedad llamada ItemsSource2D
que se utiliza para enlazar contra fuentes 2D o 1D. La biblioteca se puede descargar here y el código fuente se puede descargar here .
Para usarlo solo agregue una referencia a DataGrid2DLibrary.dll, agregue este espacio de nombres
xmlns:dg2d="clr-namespace:DataGrid2DLibrary;assembly=DataGrid2DLibrary"
y luego crea un DataGrid2D y vincúlalo a tu IList, matriz 2D o matriz 1D como este
<dg2d:DataGrid2D Name="dataGrid2D"
ItemsSource2D="{Binding Int2DList}"/>
ANTIGUO POST
Aquí hay una implementación que puede vincular una matriz 2D a la cuadrícula de datos WPF.
Digamos que tenemos esta matriz 2D
private int[,] m_intArray = new int[5, 5];
...
for (int i = 0; i < 5; i++)
{
for (int j = 0; j < 5; j++)
{
m_intArray[i,j] = (i * 10 + j);
}
}
Y luego queremos vincular esta matriz 2D a WGD DataGrid y los cambios que hagamos se reflejarán en la matriz. Para hacer esto utilicé la clase Ref de Eric Lippert de this hilo.
public class Ref<T>
{
private readonly Func<T> getter;
private readonly Action<T> setter;
public Ref(Func<T> getter, Action<T> setter)
{
this.getter = getter;
this.setter = setter;
}
public T Value { get { return getter(); } set { setter(value); } }
}
Luego hice una clase de ayudante estático con un método que podría tomar una matriz 2D y devolver una vista de datos usando la clase Ref de arriba.
public static DataView GetBindable2DArray<T>(T[,] array)
{
DataTable dataTable = new DataTable();
for (int i = 0; i < array.GetLength(1); i++)
{
dataTable.Columns.Add(i.ToString(), typeof(Ref<T>));
}
for (int i = 0; i < array.GetLength(0); i++)
{
DataRow dataRow = dataTable.NewRow();
dataTable.Rows.Add(dataRow);
}
DataView dataView = new DataView(dataTable);
for (int i = 0; i < array.GetLength(0); i++)
{
for (int j = 0; j < array.GetLength(1); j++)
{
int a = i;
int b = j;
Ref<T> refT = new Ref<T>(() => array[a, b], z => { array[a, b] = z; });
dataView[i][j] = refT;
}
}
return dataView;
}
Esto sería casi suficiente para enlazar, pero la ruta en el enlace señalará el objeto Ref en lugar del Ref.Value que necesitamos, así que tenemos que cambiar esto cuando se generen las columnas.
<DataGrid Name="c_dataGrid"
RowHeaderWidth="0"
ColumnHeaderHeight="0"
AutoGenerateColumns="True"
AutoGeneratingColumn="c_dataGrid_AutoGeneratingColumn"/>
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");
}
Y después de esto podemos usar
c_dataGrid.ItemsSource = BindingHelper.GetBindable2DArray<int>(m_intArray);
Y la salida se verá así
Cualquier cambio realizado en DataGrid
se reflejará en m_intArray.
El propósito de la Grilla no es el enlace de datos real, es solo un panel. Estoy enumerando la forma más fácil de lograr la visualización de una lista bidimensional
<Window.Resources>
<DataTemplate x:Key="DataTemplate_Level2">
<Button Content="{Binding}" Height="40" Width="50" Margin="4,4,4,4"/>
</DataTemplate>
<DataTemplate x:Key="DataTemplate_Level1">
<ItemsControl ItemsSource="{Binding}" ItemTemplate="{DynamicResource DataTemplate_Level2}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</DataTemplate>
</Window.Resources>
<Grid>
<ItemsControl x:Name="lst" ItemTemplate="{DynamicResource DataTemplate_Level1}"/>
</Grid>
Y en el código detrás de set el ItemsSource de lst con una estructura de datos TwoDimentional.
public Window1()
{
List<List<int>> lsts = new List<List<int>>();
for (int i = 0; i < 5; i++)
{
lsts.Add(new List<int>());
for (int j = 0; j < 5; j++)
{
lsts[i].Add(i * 10 + j);
}
}
InitializeComponent();
lst.ItemsSource = lsts;
}
Esto le da la siguiente pantalla como salida. Puede editar DataTemplate_Level2 para agregar datos más específicos de su objeto.
Es posible que desee consultar este enlace: http://www.thinkbottomup.com.au/site/blog/Game_of_Life_in_XAML_WPF_using_embedded_Python
Si usa una Lista dentro de una Lista, puede usar myList [x] [y] para acceder a una celda.
Escribí una pequeña biblioteca de propiedades adjuntas para DataGrid
. Aquí está la fuente
Muestra, donde Data2D es int[,]
:
<DataGrid HeadersVisibility="None"
dataGrid2D:Source2D.ItemsSource2D="{Binding Data2D}" />
Renders: