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