I need to fill an panel with clickable button-based cells that looks like this:
this has done with rectangles:
<ItemsControl ItemsSource="{Binding Path=Cells}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Rectangle>
<Rectangle.Fill>
<SolidColorBrush Color="Red"></SolidColorBrush>
</Rectangle.Fill>
</Rectangle>
</DataTemplate>
</ItemsControl.ItemTemplate>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<commonControls:UniformGrid ElementsGap="5" HorizontalCount="{Binding Path=CellsInRow}" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
but I need to do it with buttons. I'm trying that:
<ItemsControl ItemsSource="{Binding Path=Cells}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Button>
<Button.Background>
<SolidColorBrush Color="Red"></SolidColorBrush>
</Button.Background>
</Button>
</DataTemplate>
</ItemsControl.ItemTemplate>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<commonControls:UniformGrid ElementsGap="5" HorizontalCount="{Binding Path=CellsInRow}" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
But it seems like that:
How i can do cells from first image with buttons?
Code of UniformGrid below:
public class UniformGrid : Panel
{
public static readonly DependencyProperty HorizontalCountProperty =
DependencyProperty.Register("HorizontalCount", typeof (int), typeof (UniformGrid),
new PropertyMetadata(default(int)));
public int HorizontalCount
{
get { return (int) GetValue(HorizontalCountProperty); }
set { SetValue(HorizontalCountProperty, value); }
}
public static readonly DependencyProperty ElementsGapProperty =
DependencyProperty.Register("ElementsGap", typeof (double), typeof (UniformGrid),
new PropertyMetadata(default(double)));
public double ElementsGap
{
get { return (double) GetValue(ElementsGapProperty); }
set { SetValue(ElementsGapProperty, value); }
}
protected override Size MeasureOverride(Size availableSize)
{
return new Size();
}
protected override Size ArrangeOverride(Size finalSize)
{
if (Children != null && Children.Count != 0)
{
var squareSideForElement = (finalSize.Width - (HorizontalCount - 1)*ElementsGap)/HorizontalCount;
var sizeOfElement = new Size(squareSideForElement, squareSideForElement);
for (var i = 0; i < Children.Count; i++)
{
var rowIndex = i%HorizontalCount;
var columnIndex = i/HorizontalCount;
var resultPoint = new Point
{
X = rowIndex*(squareSideForElement + ElementsGap),
Y = columnIndex*(squareSideForElement + ElementsGap)
};
Children[i].Arrange(new Rect(resultPoint, sizeOfElement));
}
}
return finalSize;
}
}
Your MeasureOverride must call Measure on each child. Please read the Remarks section in MeasureOverride, especially the following note:
Elements should call Measure on each child during this process, otherwise the child elements will not be correctly sized or arranged
You should at least do this:
protected override Size MeasureOverride(Size availableSize)
{
foreach (UIElement element in InternalChildren)
{
element.Measure(availableSize);
}
return new Size();
}
If you want to make sure that every child calculates its maximum preferred size, you could pass an infinite width and height to Measure:
protected override Size MeasureOverride(Size availableSize)
{
availableSize = new Size(double.PositiveInfinity, double.PositiveInfinity);
foreach (UIElement element in InternalChildren)
{
element.Measure(availableSize);
}
return new Size();
}