Skip to content

Commit 1d31e54

Browse files
Merge pull request #4104 from michael-hawker/constrained-presenter
Add initial ConstrainedBox control for AspectRatio and Scaling
2 parents 6f8d29f + a9cc874 commit 1d31e54

31 files changed

+893
-20
lines changed
Binary file not shown.
161 Bytes
Loading
-1.07 KB
Binary file not shown.

Microsoft.Toolkit.Uwp.SampleApp/Microsoft.Toolkit.Uwp.SampleApp.csproj

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<Project ToolsVersion="15.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
1+
<Project ToolsVersion="15.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
22
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
33
<PropertyGroup>
44
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
@@ -130,6 +130,7 @@
130130
<!-- A reference to the entire .Net Framework and Windows SDK are automatically included -->
131131
<Content Include="Assets\BrushAssets\TileTexture.png" />
132132
<Content Include="Assets\BrushAssets\NoiseTexture.png" />
133+
<Content Include="Assets\checker.png" />
133134
<Content Include="Assets\Llama.mp3" />
134135
<Content Include="Assets\mslogo.png" />
135136
<Content Include="Assets\NotificationAssets\Cloudy-Square.png" />
@@ -271,6 +272,7 @@
271272
<Content Include="SamplePages\Graph\LoginButton.png" />
272273
<Content Include="SamplePages\Graph\PeoplePicker.png" />
273274
<Content Include="SamplePages\Graph\PersonView.png" />
275+
<Content Include="SamplePages\Primitives\ConstrainedBox.png" />
274276
<Content Include="SamplePages\Primitives\SwitchPresenter.png" />
275277
<Content Include="SamplePages\TabbedCommandBar\TabbedCommandBar.png" />
276278
<Content Include="SamplePages\Animations\Effects\FadeBehavior.png" />
@@ -621,6 +623,9 @@
621623
<Content Include="SamplePages\Graph\PeoplePickerXaml.bind" />
622624
<Content Include="SamplePages\Graph\PersonViewXaml.bind" />
623625
<Content Include="SamplePages\ListViewExtensions\ListViewExtensionsCode.bind" />
626+
<Content Include="SamplePages\Primitives\ConstrainedBox.bind">
627+
<SubType>Designer</SubType>
628+
</Content>
624629
</ItemGroup>
625630
<ItemGroup>
626631
<Compile Include="App.xaml.cs">
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<Page
2+
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
3+
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
4+
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
5+
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
6+
xmlns:controls="using:Microsoft.Toolkit.Uwp.UI.Controls"
7+
xmlns:brushes="using:Microsoft.Toolkit.Uwp.UI.Media"
8+
mc:Ignorable="d">
9+
10+
<Grid>
11+
<controls:ConstrainedBox AspectRatio="16:3" VerticalAlignment="Top">
12+
<Image Source="/Assets/Photos/WestSeattleView.jpg"
13+
Stretch="UniformToFill"
14+
VerticalAlignment="Center"/> <!-- Center on the City -->
15+
</controls:ConstrainedBox>
16+
<controls:ConstrainedBox MultipleX="64"
17+
AspectRatio="1:1"
18+
MinWidth="64" MaxWidth="512">
19+
<controls:ConstrainedBox.Background>
20+
<!-- TODO: TilesBrush doesn't support Dpi image loading for this scenario
21+
This example is configured for 100% DPI at the moment.
22+
See https://github.com/CommunityToolkit/WindowsCommunityToolkit/issues/4150
23+
-->
24+
<brushes:TilesBrush TextureUri="ms-appx:///Assets/checker.png"/>
25+
</controls:ConstrainedBox.Background>
26+
</controls:ConstrainedBox>
27+
</Grid>
28+
</Page>
Loading

Microsoft.Toolkit.Uwp.SampleApp/SamplePages/XamlOnlyPage.xaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@
4747
<controls:Case IsDefault="True" />
4848
</controls:CaseCollection>
4949
</controls:SwitchPresenter>
50+
<controls:ConstrainedBox x:Key="ConstrainedBoxControl" />
5051
</Page.Resources>
5152

5253
<Grid>

Microsoft.Toolkit.Uwp.SampleApp/SamplePages/samples.json

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -475,6 +475,15 @@
475475
"XamlCodeFile": "/SamplePages/Primitives/SwitchPresenter.bind",
476476
"Icon": "/SamplePages/Primitives/SwitchPresenter.png",
477477
"DocumentationUrl": "https://raw.githubusercontent.com/MicrosoftDocs/WindowsCommunityToolkitDocs/master/docs/controls/SwitchPresenter.md"
478+
},
479+
{
480+
"Name": "ConstrainedBox",
481+
"Subcategory": "Layout",
482+
"About": "The ConstrainedBox is a FrameworkElement which can allow a developer to constrain the scale, multiple of, or aspect ratio of its content.",
483+
"CodeUrl": "https://github.com/CommunityToolkit/WindowsCommunityToolkit/tree/main/Microsoft.Toolkit.Uwp.UI.Controls.Primitives/ConstrainedBox",
484+
"XamlCodeFile": "/SamplePages/Primitives/ConstrainedBox.bind",
485+
"Icon": "/SamplePages/Primitives/ConstrainedBox.png",
486+
"DocumentationUrl": "https://raw.githubusercontent.com/MicrosoftDocs/WindowsCommunityToolkitDocs/master/docs/controls/ConstrainedBox.md"
478487
}
479488
]
480489
},
@@ -1259,4 +1268,4 @@
12591268
}
12601269
]
12611270
}
1262-
]
1271+
]
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
// See the LICENSE file in the project root for more information.
4+
5+
using System;
6+
7+
namespace Microsoft.Toolkit.Uwp.UI.Controls
8+
{
9+
/// <summary>
10+
/// The <see cref="AspectRatio"/> structure is used by the <see cref="ConstrainedBox"/> control to
11+
/// define a specific ratio to restrict its content.
12+
/// </summary>
13+
[Windows.Foundation.Metadata.CreateFromString(MethodName = "Microsoft.Toolkit.Uwp.UI.Controls.AspectRatio.ConvertToAspectRatio")]
14+
public readonly struct AspectRatio
15+
{
16+
/// <summary>
17+
/// Gets the width component of the aspect ratio or the aspect ratio itself (and height will be 1).
18+
/// </summary>
19+
public double Width { get; }
20+
21+
/// <summary>
22+
/// Gets the height component of the aspect ratio.
23+
/// </summary>
24+
public double Height { get; }
25+
26+
/// <summary>
27+
/// Gets the raw numeriucal aspect ratio value itself (Width / Height).
28+
/// </summary>
29+
public double Value => Width / Height;
30+
31+
/// <summary>
32+
/// Initializes a new instance of the <see cref="AspectRatio"/> struct with the provided width and height.
33+
/// </summary>
34+
/// <param name="width">Width side of the ratio.</param>
35+
/// <param name="height">Height side of the ratio.</param>
36+
public AspectRatio(double width, double height)
37+
{
38+
Width = width;
39+
Height = height;
40+
}
41+
42+
/// <summary>
43+
/// Initializes a new instance of the <see cref="AspectRatio"/> struct with the specific numerical aspect ratio.
44+
/// </summary>
45+
/// <param name="ratio">Raw Aspect Ratio, Height will be 1.</param>
46+
public AspectRatio(double ratio)
47+
{
48+
Width = ratio;
49+
Height = 1;
50+
}
51+
52+
/// <summary>
53+
/// Implicit conversion operator to convert an <see cref="AspectRatio"/> to a <see cref="double"/> value.
54+
/// This lets you use them easily in mathmatical expressions.
55+
/// </summary>
56+
/// <param name="aspect"><see cref="AspectRatio"/> instance.</param>
57+
public static implicit operator double(AspectRatio aspect) => aspect.Value;
58+
59+
/// <summary>
60+
/// Implicit conversion operator to convert a <see cref="double"/> to an <see cref="AspectRatio"/> value.
61+
/// This allows for x:Bind to bind to a double value.
62+
/// </summary>
63+
/// <param name="ratio"><see cref="double"/> value representing the <see cref="AspectRatio"/>.</param>
64+
public static implicit operator AspectRatio(double ratio) => new AspectRatio(ratio);
65+
66+
/// <summary>
67+
/// Converter to take a string aspect ration like "16:9" and convert it to an <see cref="AspectRatio"/> struct.
68+
/// Used automatically by XAML.
69+
/// </summary>
70+
/// <param name="rawString">The string to be converted in format "Width:Height" or a decimal value.</param>
71+
/// <returns>The <see cref="AspectRatio"/> struct representing that ratio.</returns>
72+
public static AspectRatio ConvertToAspectRatio(string rawString)
73+
{
74+
string[] ratio = rawString.Split(":");
75+
76+
if (ratio.Length == 2)
77+
{
78+
return new AspectRatio(Convert.ToDouble(ratio[0]), Convert.ToDouble(ratio[1]));
79+
}
80+
else if (ratio.Length == 1)
81+
{
82+
return new AspectRatio(Convert.ToDouble(ratio[0]));
83+
}
84+
85+
return new AspectRatio(1);
86+
}
87+
88+
/// <inheritdoc/>
89+
public override string ToString()
90+
{
91+
return Width + ":" + Height;
92+
}
93+
}
94+
}
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
// See the LICENSE file in the project root for more information.
4+
5+
using System;
6+
using System.Collections.Generic;
7+
using System.Linq;
8+
using System.Text;
9+
using System.Threading.Tasks;
10+
using Windows.Foundation;
11+
using Windows.UI.Xaml;
12+
using Windows.UI.Xaml.Controls;
13+
14+
namespace Microsoft.Toolkit.Uwp.UI.Controls
15+
{
16+
/// <summary>
17+
/// Dependency properties for the <see cref="ConstrainedBox"/> class.
18+
/// </summary>
19+
public partial class ConstrainedBox
20+
{
21+
/// <summary>
22+
/// Gets or sets the scale for the width of the panel. Should be a value between 0-1.0. Default is 1.0.
23+
/// </summary>
24+
public double ScaleX
25+
{
26+
get { return (double)GetValue(ScaleXProperty); }
27+
set { SetValue(ScaleXProperty, value); }
28+
}
29+
30+
/// <summary>
31+
/// Identifies the <see cref="ScaleX"/> property.
32+
/// </summary>
33+
public static readonly DependencyProperty ScaleXProperty =
34+
DependencyProperty.Register(nameof(ScaleX), typeof(double), typeof(ConstrainedBox), new PropertyMetadata(1.0, ConstraintPropertyChanged));
35+
36+
/// <summary>
37+
/// Gets or sets the scale for the height of the panel. Should be a value between 0-1.0. Default is 1.0.
38+
/// </summary>
39+
public double ScaleY
40+
{
41+
get { return (double)GetValue(ScaleYProperty); }
42+
set { SetValue(ScaleYProperty, value); }
43+
}
44+
45+
/// <summary>
46+
/// Identifies the <see cref="ScaleY"/> property.
47+
/// </summary>
48+
public static readonly DependencyProperty ScaleYProperty =
49+
DependencyProperty.Register(nameof(ScaleY), typeof(double), typeof(ConstrainedBox), new PropertyMetadata(1.0, ConstraintPropertyChanged));
50+
51+
/// <summary>
52+
/// Gets or sets the integer multiple that the width of the panel should be floored to. Default is null (no snap).
53+
/// </summary>
54+
public int MultipleX
55+
{
56+
get { return (int)GetValue(MultipleXProperty); }
57+
set { SetValue(MultipleXProperty, value); }
58+
}
59+
60+
/// <summary>
61+
/// Identifies the <see cref="MultipleX"/> property.
62+
/// </summary>
63+
public static readonly DependencyProperty MultipleXProperty =
64+
DependencyProperty.Register(nameof(MultipleX), typeof(int), typeof(ConstrainedBox), new PropertyMetadata(null));
65+
66+
/// <summary>
67+
/// Gets or sets the integer multiple that the height of the panel should be floored to. Default is null (no snap).
68+
/// </summary>
69+
public int MultipleY
70+
{
71+
get { return (int)GetValue(MultipleYProperty); }
72+
set { SetValue(MultipleYProperty, value); }
73+
}
74+
75+
/// <summary>
76+
/// Identifies the <see cref="MultipleY"/> property.
77+
/// </summary>
78+
public static readonly DependencyProperty MultipleYProperty =
79+
DependencyProperty.Register(nameof(MultipleY), typeof(int), typeof(ConstrainedBox), new PropertyMetadata(null));
80+
81+
/// <summary>
82+
/// Gets or sets aspect Ratio to use for the contents of the Panel (after scaling).
83+
/// </summary>
84+
public AspectRatio AspectRatio
85+
{
86+
get { return (AspectRatio)GetValue(AspectRatioProperty); }
87+
set { SetValue(AspectRatioProperty, value); }
88+
}
89+
90+
/// <summary>
91+
/// Identifies the <see cref="AspectRatio"/> property.
92+
/// </summary>
93+
public static readonly DependencyProperty AspectRatioProperty =
94+
DependencyProperty.Register(nameof(AspectRatio), typeof(AspectRatio), typeof(ConstrainedBox), new PropertyMetadata(null, ConstraintPropertyChanged));
95+
96+
private static void ConstraintPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
97+
{
98+
if (d is ConstrainedBox panel)
99+
{
100+
panel.InvalidateMeasure();
101+
}
102+
}
103+
}
104+
}

0 commit comments

Comments
 (0)