Skip to content

Commit 64b2b91

Browse files
Update BoxPanel custom panel example
Used this as an example for a template we're building in the Windows Community Toolkit and ran into some issues with the sample and code. Figured I'd contribute back to the article here the fixes I had to do. Fixes: - Off-by-one logic error for cutting size of box (for instance try '6' as a value, should be 2x3 not 3x3 still) (from my understanding of the scenario) - Missing `{` in `LimitUnboundedSize` method - Missing `;` in `ArrangeOverride` method - Improper definition of a Dependency Property (guidelines are strict here about property and DP names aligning otherwise issues can occur, picked a more standard XAML based Panel name here as well for this scenario. - Also added changed callback to invalidate layout so that the dependency property change actually updates the layout of the control immediately. - Provided more context for where the adjustment to the code goes.
1 parent 7a82c09 commit 64b2b91

File tree

1 file changed

+26
-12
lines changed

1 file changed

+26
-12
lines changed

hub/apps/design/layout/boxpanel-example-custom-panel.md

Lines changed: 26 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -95,11 +95,11 @@ protected override Size MeasureOverride(Size availableSize)
9595
if (aspectratio > 1)
9696
{
9797
rowcount = maxrc;
98-
colcount = (maxrc > 2 && Children.Count < maxrc * (maxrc - 1)) ? maxrc - 1 : maxrc;
98+
colcount = (maxrc > 2 && Children.Count <= maxrc * (maxrc - 1)) ? maxrc - 1 : maxrc;
9999
}
100100
else
101101
{
102-
rowcount = (maxrc > 2 && Children.Count < maxrc * (maxrc - 1)) ? maxrc - 1 : maxrc;
102+
rowcount = (maxrc > 2 && Children.Count <= maxrc * (maxrc - 1)) ? maxrc - 1 : maxrc;
103103
colcount = maxrc;
104104
}
105105

@@ -135,9 +135,8 @@ However, the panel itself can't return a [**Size**](/uwp/api/Windows.Foundation.
135135
// That can happen to height if the panel is close to the root of main app window.
136136
// In this case, base the height of a cell on the max height from desired size
137137
// and base the height of the panel on that number times the #rows.
138-
139138
Size LimitUnboundedSize(Size input)
140-
139+
{
141140
if (Double.IsInfinity(input.Height))
142141
{
143142
input.Height = maxcellheight * colcount;
@@ -152,7 +151,7 @@ Size LimitUnboundedSize(Size input)
152151
```CSharp
153152
protected override Size ArrangeOverride(Size finalSize)
154153
{
155-
int count = 1
154+
int count = 1;
156155
double x, y;
157156
foreach (UIElement child in Children)
158157
{
@@ -183,20 +182,35 @@ It's typical that the input *finalSize* and the [**Size**](/uwp/api/Windows.Foun
183182
You could compile and use this panel just as it is now. However, we'll add one more refinement. In the code just shown, the logic puts the extra row or column on the side that's longest in aspect ratio. But for greater control over the shapes of cells, it might be desirable to choose a 4x3 set of cells instead of 3x4 even if the panel's own aspect ratio is "portrait." So we'll add an optional dependency property that the panel consumer can set to control that behavior. Here's the dependency property definition, which is very basic:
184183

185184
```CSharp
186-
public static readonly DependencyProperty UseOppositeRCRatioProperty =
187-
DependencyProperty.Register("UseOppositeRCRatio", typeof(bool), typeof(BoxPanel), null);
185+
// Property
186+
public Orientation Orientation
187+
{
188+
get { return (Orientation)GetValue(OrientationProperty); }
189+
set { SetValue(OrientationProperty, value); }
190+
}
188191

189-
public bool UseSquareCells
192+
// Dependency Property Registration
193+
public static readonly DependencyProperty OrientationProperty =
194+
DependencyProperty.Register(nameof(Orientation), typeof(Orientation), typeof(BoxPanel), new PropertyMetadata(null, OnOrientationChanged));
195+
196+
// Changed callback so we invalidate our layout when the property changes.
197+
private static void OnOrientationChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs args)
190198
{
191-
get { return (bool)GetValue(UseOppositeRCRatioProperty); }
192-
set { SetValue(UseOppositeRCRatioProperty, value); }
199+
if (dependencyObject is BoxPanel panel)
200+
{
201+
panel.InvalidateMeasure();
202+
}
193203
}
194204
```
195205

196-
And here's how using `UseOppositeRCRatio` impacts the measure logic. Really all it's doing is changing how `rowcount` and `colcount` are derived from `maxrc` and the true aspect ratio, and there are corresponding size differences for each cell because of that. When `UseOppositeRCRatio` is **true**, it inverts the value of the true aspect ratio before using it for row and column counts.
206+
And below is how using `Orientation` impacts the measure logic in `MeasureOverride`. Really all it's doing is changing how `rowcount` and `colcount` are derived from `maxrc` and the true aspect ratio, and there are corresponding size differences for each cell because of that. When `Orientation` is **Vertical** (default), it inverts the value of the true aspect ratio before using it for row and column counts for our "portrait" rectangle layout.
197207

198208
```CSharp
199-
if (UseSquareCells) { aspectratio = 1 / aspectratio;}
209+
// Get an aspect ratio from availableSize, decides whether to trim row or column.
210+
aspectratio = availableSize.Width / availableSize.Height;
211+
212+
// Transpose aspect ratio based on Orientation property.
213+
if (Orientation == Orientation.Vertical) { aspectratio = 1 / aspectratio; }
200214
```
201215

202216
## The scenario for BoxPanel

0 commit comments

Comments
 (0)