Comment remplir une grille WPF basée sur un tableau bidimensionnel

j'ai un tableau bidimensionnel d'objets et je veux essentiellement databind chacun à une cellule dans une grille WPF. À l'heure actuelle, cela fonctionne, mais je le fais essentiellement sur le plan de la procédure. J'ai créer le nombre de ligne et de colonne définitions, puis je boucle dans les cellules et créer les contrôles et de configurer correctement les liaisons pour chacun.

au minimum, je voudrais pouvoir utiliser un modèle pour spécifier les contrôles et les fixations dans xaml. Idéalement, J' j'aimerais me débarrasser du code de procédure et tout faire avec la databinding, mais je ne suis pas sûr que ce soit possible.

Voici le code que j'utilise actuellement:

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

}
54
demandé sur Daniel Plaisted 2008-11-10 04:05:52

5 réponses

le but de la grille n'est pas de créer de véritables bases de données, c'est juste un panneau. Je liste vers le bas la façon la plus facile d'accomplir la visualisation d'une liste bidimensionnelle

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

et dans le code derrière définir le ItemsSource de lst avec une structure de données bidimensionnelle.

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

Cela vous donne l'écran suivant la sortie. Vous pouvez éditer le Datatatemplate_level2 pour ajouter des données plus spécifiques de votre objet.

alt text

62
répondu Jobi Joy 2015-07-27 10:41:03

voici un contrôle appelé DataGrid2D qui peut être peuplé sur la base D'une 2D ou

Tableau 1D (ou tout ce qui implémente l'interface IList ). Il Classe DataGrid et ajoute une propriété appelée ItemsSource2D qui est utilisée pour la liaison avec des sources 2D ou 1D. La bibliothèque peut être téléchargée ici et le code source peut être téléchargé ici .

Pour l'utiliser il suffit d'ajouter une référence à DataGrid2DLibrary.dll, ajouter ce namespace

xmlns:dg2d="clr-namespace:DataGrid2DLibrary;assembly=DataGrid2DLibrary"

et ensuite créer un DataGrid2D et le lier à votre IList, 2D array ou 1D array comme ceci

<dg2d:DataGrid2D Name="dataGrid2D"
                 ItemsSource2D="{Binding Int2DList}"/>

enter image description here


OLD POST

Voici une implémentation qui peut lier un tableau 2D au datagrid WPF.

dites que nous avons ce 2D array

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

et ensuite nous voulons lier ce tableau 2D à la base de données WPF et les changements que nous faisons seront reflétés dans le tableau. Pour ce faire, J'ai utilisé la classe Ref D'Eric Lippert de ce "fil 1519160920".

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

puis j'ai fait une classe d'Assistant statique avec une méthode qui pourrait prendre un tableau 2D et retourner un DataView en utilisant la classe Ref ci-dessus.

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

ce serait presque suffisant pour lier à mais le Chemin d'accès dans la Liaison point à la Réf de l'objet au lieu de l'Réf.Valeur dont nous avons besoin donc nous devons changer cela lorsque les colonnes sont générées.

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

et après cela nous pouvons utiliser

c_dataGrid.ItemsSource = BindingHelper.GetBindable2DArray<int>(m_intArray);

et la sortie ressemblera à ceci

alt text

tout changement apporté au DataGrid sera reflété dans le m_intArray.

42
répondu Fredrik Hedblad 2017-05-23 11:33:13

j'ai écrit une petite bibliothèque de propriétés attachées pour la DataGrid . Voici la source

échantillon, où Data2D est int[,] :

<DataGrid HeadersVisibility="None"
          dataGrid2D:Source2D.ItemsSource2D="{Binding Data2D}" />

rend: enter image description here

3
répondu Johan Larsson 2015-06-28 18:08:23

vous pouvez consulter ce lien: http://www.thinkbottomup.com.au/site/blog/Game_of_Life_in_XAML_WPF_using_embedded_Python

Si vous utilisez une Liste dans une Liste, vous pouvez utiliser myList[x][y] pour accéder à une cellule.

0
répondu Torsten 2009-10-28 09:19:50

Voici une autre solution basée sur Meleak 'S réponse mais sans exiger pour un AutoGeneratingColumn event handler dans le code derrière de chaque lié DataGrid :

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;
}
0
répondu CitizenInsane 2017-05-23 12:10:54