Pergunta

Eu tenho uma matriz de 2 dimensões dos objetos e Basicamente, eu quero vincular cada um para uma célula em uma grade WPF. Atualmente eu tenho esse trabalho, mas eu estou fazendo mais do mesmo processualmente. I criar o número correcto de definições de linha e coluna, em seguida, repetir I através das células e os controles de criar e configurar as ligações correctas para cada um.

No mínimo eu gostaria de ser capaz de usar um modelo para especificar os controles e ligações em XAML. Idealmente, eu gostaria de se livrar do código de procedimento e apenas fazê-lo todos com ligação de dados, mas eu não tenho certeza de que isso é possível.

Aqui está o código que estou usando atualmente:

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

}
Foi útil?

Solução

O objetivo da grade não é para ligação de dados real, é apenas um painel. Estou listando para baixo a maneira mais fácil para realizar a visualização de uma lista de dois dimensional

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

E no código por trás definir o ItemsSource do lst com uma estrutura de dados 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;
    }

Isto dá-lhe a seguinte tela como saída. Você pode editar o DataTemplate_Level2 para adicionar dados mais específicos do seu objeto.

text alt

Outras dicas

Aqui está um controle chamado DataGrid2D que podem ser preenchidos com base em um 2D ou
1D matriz (ou qualquer coisa que implementa a interface IList). Ele subclasses DataGrid e adiciona uma propriedade chamada ItemsSource2D que é usado para a ligação contra fontes 2D ou 1D. Biblioteca pode ser baixado aqui e código-fonte pode ser baixado aqui .

Para usá-lo basta adicionar uma referência para DataGrid2DLibrary.dll, adicione este namespace

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

e, em seguida, criar um DataGrid2D e vinculá-lo à sua IList, matriz 2D ou matriz 1D como este

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

enter descrição da imagem aqui


OLD POST
Aqui está uma implementação que pode vincular uma matriz 2D para o datagrid WPF.

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

E então queremos vincular essa matriz 2D para o WPF DataGrid e as mudanças que fazemos deve reflectir-se na matriz. Para fazer isso eu usei classe Ref de Eric Lippert de esta discussão .

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

Então eu fiz uma classe auxiliar estática com um método que poderia tomar uma matriz 2D e retornar um DataView usando a classe Ref acima.

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

Este seria quase suficiente para vincular a, mas o caminho na ligação irá apontar para o objeto Ref vez do Ref.Value que nós precisamos por isso temos de mudar isso quando as colunas são geradas.

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

E, depois disso, podemos usar

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

E a saída será semelhante a este

text alt

Todas as alterações feitas no DataGrid será refletido no m_intArray.

Eu escrevi uma pequena biblioteca de propriedades anexadas para o DataGrid. Aqui está a fonte

Sample, onde Data2D é int[,]:

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

Renders: enter descrição da imagem aqui

Você pode querer confira este link: http: //www.thinkbottomup. com.au/site/blog/Game_of_Life_in_XAML_WPF_using_embedded_Python

Se você usar uma lista dentro de uma lista que você pode usar myList [x] [y] para acessar uma célula.

Aqui está outra solução baseada na resposta Meleak 's, mas sem a necessidade de um manipulador de eventos AutoGeneratingColumn no código por trás de cada DataGrid Binded:

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;
}
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top