Frage

Ich habe einen 2-dimensionalen Array von Objekten und ich mag im Grunde jedes auf eine Zelle in einem WPF-Raster Databind. Zur Zeit habe ich diese Arbeit, aber ich das meiste davon prozedural tue. Ich schaffe die richtige Anzahl von Zeilen- und Spaltendefinitionen, dann I-Schleife durch die Zellen und die Kontrollen erstellen und die richtigen Bindungen für jeden einrichten.

Als Minimum würde Ich mag die Lage sein, eine Vorlage zu verwenden, um die Kontrollen und Bindungen in XAML festlegen. Im Idealfall würde Ich mag die Beseitigung des prozeduralen Code erhalten und tue einfach alles mit Datenbindung, aber ich bin nicht sicher, ob das möglich ist.

Hier ist der Code, den ich zur Zeit bin mit:

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

}
War es hilfreich?

Lösung

Der Zweck des Grid ist nicht für echte Datenbindung, es ist nur eine Platte. Mir Streichungen den einfachste Weg, um die Visualisierung einer zweidimensionale Liste zu erreichen

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

Und in der Code-behind stellen Sie die Itemssource von lst mit TwoDimentional Datenstruktur.

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

Das gibt Ihnen den folgenden Bildschirm als Ausgabe. Sie können die DataTemplate_Level2 bearbeiten spezifischere Daten des Objekts hinzuzufügen.

alt text

Andere Tipps

Hier ist ein Steuer DataGrid2D genannt, die auf einem 2D bevölkerten basieren können oder in 1D-Array (oder irgendetwas, das die Schnittstelle implementiert IList). Es Unterklassen DataGrid und fügt eine Eigenschaft namens ItemsSource2D die für die Bindung an 2D oder 1D Quellen verwendet wird. Bibliothek können hier heruntergeladen werden und der Quellcode kann heruntergeladen werden hier .

Um es zu benutzen Sie einfach einen Verweis auf DataGrid2DLibrary.dll hinzufügen, fügen Sie diesen Namespace

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

und dann eine DataGrid2D erstellen und binden Sie es an Ihre IList, 2D-Array oder 1D Array wie folgt

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

eingeben Bild Beschreibung hier


ALTE POST
Hier ist eine Implementierung, die ein 2D-Array an die WPF Datagrid binden kann.

Sagen wir diesen 2D-Array haben

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

Und dann wollen wir diesen 2D-Array mit der WPF-Datagrid und den Änderungen binden wir im Array machen soll reflektiert werden. Um dies zu tun habe ich Eric Lippert Ref Klasse von dieser Thread.

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

Dann habe ich eine statische Hilfsklasse mit einem Verfahren, das einen 2D-Array nehmen und eine Dataview zurückzukehren über die Ref-Klasse.

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

Dies würde fast genug sein, um zu binden, aber der Weg in der Bindung wird verweisen auf die Ref anstelle der Ref.Value Objekt, das wir brauchen, so müssen wir dies ändern, wenn die Spalten erzeugt erhalten.

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

Und danach können wir verwenden

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

Und die Ausgabe wird wie folgt aussehen

alt text

Jede in den DataGrid vorgenommenen Änderungen in der m_intArray reflektiert werden.

Ich schrieb eine kleine Bibliothek von angefügten Eigenschaften für die DataGrid. Hier ist die Quelle

Beispiel, wo Data2D ist int[,]:

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

Renders: eingeben Bild Beschreibung hier

Sie können diesen Link prüfen wollen: http: //www.thinkbottomup. com.au/site/blog/Game_of_Life_in_XAML_WPF_using_embedded_Python

Wenn Sie eine Liste in einer Liste verwenden, können Sie myList [x] [y] verwenden, um eine Zelle zu gelangen.

Hier ist ein andere Lösung basiert auf Meleak 's Antwort, aber ohne dass für einen AutoGeneratingColumn Event-Handler in dem Code hinter dem jede binded 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;
}
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top