Laden...

Positionierung von Elementen innerhalb von UniformGrid -> wie?

Erstellt von wackelkontakt vor 12 Jahren Letzter Beitrag vor 12 Jahren 3.908 Views
wackelkontakt Themenstarter:in
109 Beiträge seit 2011
vor 12 Jahren
Positionierung von Elementen innerhalb von UniformGrid -> wie?

Hallo,

wie ich mittlerweile herausgefunden habe ist eine explizite Positionierung von Elementen innerhalb des UniformGrids nicht möglich. Deshalb geht unteres Beispiel schief:


<ItemsControl ItemsSource ="{Binding Path=Cells}">
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <Button                            
                Grid.Column="{Binding Cell.PositionX}"
                Grid.Row="{Binding Cell.PositionY}"
                Content="{Binding}" />
        </DataTemplate>
    </ItemsControl.ItemTemplate>
    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <UniformGrid 
                Columns ="{Binding SizeX}" 
                Rows="{Binding SizeY}"/>
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>
</ItemsControl>

Kennt jemand eine clevere Lösung um die Elemente in einem Panel sortiert angezeigt zu bekommen? Die Source zu sortieren würde ich gern vermeiden.

Danke!

Um Rekursion zu verstehen, muss man erst mal Rekursion verstehen, muss man erst mal Rekursion verstehen, ....

5.742 Beiträge seit 2007
vor 12 Jahren

Hallo wackelkontakt,

evtl. ist hier ein Canvas der passdenere Container.

wackelkontakt Themenstarter:in
109 Beiträge seit 2011
vor 12 Jahren

evtl. ist hier ein Canvas der passdenere Container.

Und die Elemente dann per Koordinaten positionieren? Hmmm.... hört sich bißchen sehr kompliziert und fehleranfällig an. Ich glaube dann komm ich vielleicht doch besser die Source zu sortieren?! Oder gibt es vielleicht noch einen anderen Vorschlag?

Um Rekursion zu verstehen, muss man erst mal Rekursion verstehen, muss man erst mal Rekursion verstehen, ....

5.742 Beiträge seit 2007
vor 12 Jahren

Und die Elemente dann per Koordinaten positionieren?

Hast du doch vor?
Oder wie genau willst du positionieren? Evtl. wäre da eine Skizze nicht schlecht.

wackelkontakt Themenstarter:in
109 Beiträge seit 2011
vor 12 Jahren

Hallo winSharp,

ich glaube eine Skizze ist nicht nötig 😃 Ich habe einfach eine Art Schachbrett und möchte dort drin meine unsortierten Cell-Elemente der Cells-Collection anordnen. Dafür gibt es in Cell die Properties X- und Y-Position. Ich bräuchte irgendwie eine Mischung aus UniformGrid (eignet sich besonders gut für mein 'Schachbrett' + das Anlegen der Dimensionen geht einfach) und Grid um die Elemente an die richtigen Stellen zu plazieren.

Bei einem Canvas müßte ich ja über die Längenangaben meine Elemente plazieren oder?

Weißt du ungefähr was ich meine? (Gugg dir sonst auch noch mal mein Code-Beispiel an)

Viele Grüße

Um Rekursion zu verstehen, muss man erst mal Rekursion verstehen, muss man erst mal Rekursion verstehen, ....

5.742 Beiträge seit 2007
vor 12 Jahren

Aha - also sozusagen ein UniformGrid, dass auch Leerzellen unterstützt, aber sonst auch gleich aufgebaut ist.

So was müsstest du wohl selbst schreiben - sollte nicht alzu komplex sein (von Panel ableiten und Measure sowie Arrange überschreiben).

5.742 Beiträge seit 2007
vor 12 Jahren

Ausgehend von dem Zusatz in Wieso kann Grid nicht als ItemsPanel verwendet werden? habe ich mich nochmal mit der Thematik beschäftigt.

Die Lösung in dem verlinkten Blog, einfach einfach ein Grid als Basis zu nehmen, ist schon deutlich besser als mein damaliger Ansatz.

Eine Ableitung muss man jedoch nicht erstellen - zwei attached Properties reichen:


public static class Autogenerate
{
    public static readonly DependencyProperty RowsProperty = DependencyProperty.RegisterAttached("Rows", typeof(int), typeof(Autogenerate), new UIPropertyMetadata(0, Rows_Changed));
    public static readonly DependencyProperty ColumnsProperty = DependencyProperty.RegisterAttached("Columns", typeof(int), typeof(Autogenerate), new UIPropertyMetadata(0, Columns_Changed));

    public static int GetRows(DependencyObject obj)
    {
        return (int) obj.GetValue(RowsProperty);
    }
    public static void SetRows(DependencyObject obj, int value)
    {
        obj.SetValue(RowsProperty, value);
    }

    public static int GetColumns(DependencyObject obj)
    {
        return (int) obj.GetValue(ColumnsProperty);
    }
    public static void SetColumns(DependencyObject obj, int value)
    {
        obj.SetValue(ColumnsProperty, value);
    }

    private static void Rows_Changed(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        Grid grid = (Grid) d;
        int rowsToAdd = ((int) e.NewValue) - grid.RowDefinitions.Count;

        while (rowsToAdd < 0)
        {
            grid.RowDefinitions.RemoveAt(0);

            rowsToAdd++;
        }
        while (rowsToAdd > 0)
        {
            grid.RowDefinitions.Add(new RowDefinition() { Height = new GridLength(1, GridUnitType.Star) });

            rowsToAdd--;
        }

    }
    private static void Columns_Changed(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        Grid grid = (Grid) d;
        int columnsToAdd = ((int) e.NewValue) - grid.ColumnDefinitions.Count;

        while (columnsToAdd < 0)
        {
            grid.ColumnDefinitions.RemoveAt(0);

            columnsToAdd++;
        }
        while (columnsToAdd > 0)
        {
            grid.ColumnDefinitions.Add(new ColumnDefinition() { Width = new GridLength(1, GridUnitType.Star) });

            columnsToAdd--;
        }
    }
}

Kleines, aber (wie ich finde 😁 ) nettes Beispielprojekt:


<Grid WpfApplication1:Autogenerate.Columns="{Binding Path=Columns}" WpfApplication1:Autogenerate.Rows="{Binding Path=Rows}">
  <Button Grid.Column="1" Grid.Row="1" Content="Remove Row" Click="Remove_Row" />
  <Button Grid.Column="0" Grid.Row="1" Content="Remove Colunm" Click="Remove_Column" />
  <Button Grid.Column="1" Grid.Row="0" Content="Add Row" Click="Add_Row" />
  <Button Grid.Column="0" Grid.Row="0" Content="Add Colunm" Click="Add_Column" />
</Grid>


public partial class MainWindow : Window
{
    private readonly Foo _foo = new Foo();

    public MainWindow()
    {
        InitializeComponent();

        this.DataContext = this._foo;
    }

    private void Remove_Row(object sender, RoutedEventArgs e)
    {
        this._foo.Rows--;
    }
    private void Remove_Column(object sender, RoutedEventArgs e)
    {
        this._foo.Columns--;
    }
    private void Add_Row(object sender, RoutedEventArgs e)
    {
        this._foo.Rows++;
    }
    private void Add_Column(object sender, RoutedEventArgs e)
    {
        this._foo.Columns++;
    }
}

public sealed class Foo
    : INotifyPropertyChanged
{
    private int _columns = 1;
    private int _rows = 1;

    public int Columns
    {
        get
        {
            return this._columns;
        }
        set
        {
            if (this.Columns == value)
                return;

            this._columns = value;
            this.OnPropertyChanged("Columns");
        }
    }
    public int Rows
    {
        get
        {
            return this._rows;
        }
        set
        {
            if (this.Rows == value)
                return;

            this._rows = value;
            this.OnPropertyChanged("Rows");
        }
    }
        
    public event PropertyChangedEventHandler PropertyChanged;

    public void OnPropertyChanged(string name)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null)
            handler(this, new PropertyChangedEventArgs(name));
    }
}