diff --git a/Microsoft.Toolkit.Uwp.SampleApp/Microsoft.Toolkit.Uwp.SampleApp.csproj b/Microsoft.Toolkit.Uwp.SampleApp/Microsoft.Toolkit.Uwp.SampleApp.csproj
index 2967f2df8ee..44027e28bc7 100644
--- a/Microsoft.Toolkit.Uwp.SampleApp/Microsoft.Toolkit.Uwp.SampleApp.csproj
+++ b/Microsoft.Toolkit.Uwp.SampleApp/Microsoft.Toolkit.Uwp.SampleApp.csproj
@@ -1079,6 +1079,10 @@
Designer
MSBuild:Compile
+
+ Designer
+ MSBuild:Compile
+
MSBuild:Compile
Designer
diff --git a/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/Triggers/ControlSizeTrigger.bind b/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/Triggers/ControlSizeTrigger.bind
new file mode 100644
index 00000000000..583f4cbbbda
--- /dev/null
+++ b/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/Triggers/ControlSizeTrigger.bind
@@ -0,0 +1,43 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/XamlOnlyPage.xaml b/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/XamlOnlyPage.xaml
index 780f14479e8..c51455532c3 100644
--- a/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/XamlOnlyPage.xaml
+++ b/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/XamlOnlyPage.xaml
@@ -31,6 +31,7 @@
+
diff --git a/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/samples.json b/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/samples.json
index 2447ae36db2..6e9841a5a36 100644
--- a/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/samples.json
+++ b/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/samples.json
@@ -920,6 +920,15 @@
"Icon": "/Assets/Helpers.png",
"DocumentationUrl": "https://raw.githubusercontent.com/MicrosoftDocs/WindowsCommunityToolkitDocs/master/docs/helpers/Triggers.md"
},
+ {
+ "Name": "ControlSizeTrigger",
+ "Subcategory": "State Triggers",
+ "About": "Enables a state if the target control meets the specified size",
+ "CodeUrl": "https://github.com/CommunityToolkit/WindowsCommunityToolkit/blob/master/Microsoft.Toolkit.Uwp.UI/Triggers/ControlSizeTrigger.cs",
+ "XamlCodeFile": "/SamplePages/Triggers/ControlSizeTrigger.bind",
+ "Icon": "/Assets/Helpers.png",
+ "DocumentationUrl": "https://raw.githubusercontent.com/MicrosoftDocs/WindowsCommunityToolkitDocs/master/docs/helpers/Triggers.md"
+ },
{
"Name": "IsEqualStateTrigger",
"Subcategory": "State Triggers",
diff --git a/Microsoft.Toolkit.Uwp.UI/Triggers/ControlSizeTrigger.cs b/Microsoft.Toolkit.Uwp.UI/Triggers/ControlSizeTrigger.cs
new file mode 100644
index 00000000000..1fcbd28291e
--- /dev/null
+++ b/Microsoft.Toolkit.Uwp.UI/Triggers/ControlSizeTrigger.cs
@@ -0,0 +1,185 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using Windows.UI.Xaml;
+
+namespace Microsoft.Toolkit.Uwp.UI.Triggers
+{
+ ///
+ /// A conditional state trigger that functions
+ /// based on the target control's width or height.
+ ///
+ public class ControlSizeTrigger : StateTriggerBase
+ {
+ ///
+ /// Gets or sets a value indicating
+ /// whether this trigger will be active or not.
+ ///
+ public bool CanTrigger
+ {
+ get => (bool)GetValue(CanTriggerProperty);
+ set => SetValue(CanTriggerProperty, value);
+ }
+
+ ///
+ /// Identifies the DependencyProperty.
+ ///
+ public static readonly DependencyProperty CanTriggerProperty = DependencyProperty.Register(
+ nameof(CanTrigger),
+ typeof(bool),
+ typeof(ControlSizeTrigger),
+ new PropertyMetadata(true, (d, e) => ((ControlSizeTrigger)d).UpdateTrigger()));
+
+ ///
+ /// Gets or sets the max width at which to trigger.
+ /// This value is exclusive, meaning this trigger
+ /// could be active if the value is less than MaxWidth.
+ ///
+ public double MaxWidth
+ {
+ get => (double)GetValue(MaxWidthProperty);
+ set => SetValue(MaxWidthProperty, value);
+ }
+
+ ///
+ /// Identifies the DependencyProperty.
+ ///
+ public static readonly DependencyProperty MaxWidthProperty = DependencyProperty.Register(
+ nameof(MaxWidth),
+ typeof(double),
+ typeof(ControlSizeTrigger),
+ new PropertyMetadata(double.PositiveInfinity, (d, e) => ((ControlSizeTrigger)d).UpdateTrigger()));
+
+ ///
+ /// Gets or sets the min width at which to trigger.
+ /// This value is inclusive, meaning this trigger
+ /// could be active if the value is >= MinWidth.
+ ///
+ public double MinWidth
+ {
+ get => (double)GetValue(MinWidthProperty);
+ set => SetValue(MinWidthProperty, value);
+ }
+
+ ///
+ /// Identifies the DependencyProperty.
+ ///
+ public static readonly DependencyProperty MinWidthProperty = DependencyProperty.Register(
+ nameof(MinWidth),
+ typeof(double),
+ typeof(ControlSizeTrigger),
+ new PropertyMetadata(0.0, (d, e) => ((ControlSizeTrigger)d).UpdateTrigger()));
+
+ ///
+ /// Gets or sets the max height at which to trigger.
+ /// This value is exclusive, meaning this trigger
+ /// could be active if the value is less than MaxHeight.
+ ///
+ public double MaxHeight
+ {
+ get => (double)GetValue(MaxHeightProperty);
+ set => SetValue(MaxHeightProperty, value);
+ }
+
+ ///
+ /// Identifies the DependencyProperty.
+ ///
+ public static readonly DependencyProperty MaxHeightProperty = DependencyProperty.Register(
+ nameof(MaxHeight),
+ typeof(double),
+ typeof(ControlSizeTrigger),
+ new PropertyMetadata(double.PositiveInfinity, (d, e) => ((ControlSizeTrigger)d).UpdateTrigger()));
+
+ ///
+ /// Gets or sets the min height at which to trigger.
+ /// This value is inclusive, meaning this trigger
+ /// could be active if the value is >= MinHeight.
+ ///
+ public double MinHeight
+ {
+ get => (double)GetValue(MinHeightProperty);
+ set => SetValue(MinHeightProperty, value);
+ }
+
+ ///
+ /// Identifies the DependencyProperty.
+ ///
+ public static readonly DependencyProperty MinHeightProperty = DependencyProperty.Register(
+ nameof(MinHeight),
+ typeof(double),
+ typeof(ControlSizeTrigger),
+ new PropertyMetadata(0.0, (d, e) => ((ControlSizeTrigger)d).UpdateTrigger()));
+
+ ///
+ /// Gets or sets the element whose width will observed
+ /// for the trigger.
+ ///
+ public FrameworkElement TargetElement
+ {
+ get => (FrameworkElement)GetValue(TargetElementProperty);
+ set => SetValue(TargetElementProperty, value);
+ }
+
+ ///
+ /// Identifies the DependencyProperty.
+ ///
+ ///
+ /// Using a DependencyProperty as the backing store for TargetElement. This enables animation, styling, binding, etc.
+ ///
+ public static readonly DependencyProperty TargetElementProperty = DependencyProperty.Register(
+ nameof(TargetElement),
+ typeof(FrameworkElement),
+ typeof(ControlSizeTrigger),
+ new PropertyMetadata(null, OnTargetElementPropertyChanged));
+
+ ///
+ /// Gets a value indicating whether the trigger is active.
+ ///
+ public bool IsActive { get; private set; }
+
+ private static void OnTargetElementPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
+ {
+ ((ControlSizeTrigger)d).UpdateTargetElement((FrameworkElement)e.OldValue, (FrameworkElement)e.NewValue);
+ }
+
+ // Handle event to get current values
+ private void OnTargetElementSizeChanged(object sender, SizeChangedEventArgs e)
+ {
+ UpdateTrigger();
+ }
+
+ private void UpdateTargetElement(FrameworkElement oldValue, FrameworkElement newValue)
+ {
+ if (oldValue != null)
+ {
+ oldValue.SizeChanged -= OnTargetElementSizeChanged;
+ }
+
+ if (newValue != null)
+ {
+ newValue.SizeChanged += OnTargetElementSizeChanged;
+ }
+
+ UpdateTrigger();
+ }
+
+ // Logic to evaluate and apply trigger value
+ private void UpdateTrigger()
+ {
+ if (TargetElement == null || !CanTrigger)
+ {
+ SetActive(false);
+ return;
+ }
+
+ bool activate = MinWidth <= TargetElement.ActualWidth &&
+ TargetElement.ActualWidth < MaxWidth &&
+ MinHeight <= TargetElement.ActualHeight &&
+ TargetElement.ActualHeight < MaxHeight;
+
+ IsActive = activate;
+ SetActive(activate);
+ }
+ }
+}
diff --git a/UnitTests/UnitTests.UWP/UI/Triggers/Test_ControlSizeTrigger.cs b/UnitTests/UnitTests.UWP/UI/Triggers/Test_ControlSizeTrigger.cs
new file mode 100644
index 00000000000..0cd0f790e1e
--- /dev/null
+++ b/UnitTests/UnitTests.UWP/UI/Triggers/Test_ControlSizeTrigger.cs
@@ -0,0 +1,125 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using Microsoft.Toolkit.Uwp;
+using Microsoft.Toolkit.Uwp.UI.Triggers;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using System.Threading.Tasks;
+using Windows.UI.Xaml.Controls;
+
+namespace UnitTests.UWP.UI.Triggers
+{
+ [TestClass]
+ [TestCategory("Test_ControlSizeTrigger")]
+ public class Test_ControlSizeTrigger : VisualUITestBase
+ {
+ [DataTestMethod]
+ [DataRow(450, 450, true)]
+ [DataRow(400, 400, true)]
+ [DataRow(500, 500, false)]
+ [DataRow(399, 400, false)]
+ [DataRow(400, 399, false)]
+ public async Task ControlSizeTriggerTest(double width, double height, bool expectedResult)
+ {
+ await App.DispatcherQueue.EnqueueAsync(async () =>
+ {
+ Grid grid = CreateGrid(width, height);
+ await SetTestContentAsync(grid);
+ var trigger = new ControlSizeTrigger();
+
+ trigger.TargetElement = grid;
+ trigger.MaxHeight = 500;
+ trigger.MinHeight = 400;
+ trigger.MaxWidth = 500;
+ trigger.MinWidth = 400;
+
+ Assert.AreEqual(expectedResult, trigger.IsActive);
+ });
+ }
+
+ [DataTestMethod]
+ [DataRow(400, 400, true)]
+ [DataRow(400, 399, false)]
+ public async Task ControlSizeMinHeightTriggerTest(double width, double height, bool expectedResult)
+ {
+ await App.DispatcherQueue.EnqueueAsync(async () =>
+ {
+ Grid grid = CreateGrid(width, height);
+ await SetTestContentAsync(grid);
+ var trigger = new ControlSizeTrigger();
+
+ trigger.TargetElement = grid;
+ trigger.MinHeight = 400;
+
+ Assert.AreEqual(expectedResult, trigger.IsActive);
+ });
+ }
+
+ [DataTestMethod]
+ [DataRow(399, 400, false)]
+ [DataRow(400, 400, true)]
+ public async Task ControlSizeMinWidthTriggerTest(double width, double height, bool expectedResult)
+ {
+ await App.DispatcherQueue.EnqueueAsync(async () =>
+ {
+ Grid grid = CreateGrid(width, height);
+ await SetTestContentAsync(grid);
+ var trigger = new ControlSizeTrigger();
+
+ trigger.TargetElement = grid;
+ trigger.MinWidth = 400;
+
+ Assert.AreEqual(expectedResult, trigger.IsActive);
+ });
+ }
+
+ [DataTestMethod]
+ [DataRow(450, 450, false)]
+ [DataRow(450, 449, true)]
+ public async Task ControlSizeMaxHeightTriggerTest(double width, double height, bool expectedResult)
+ {
+ await App.DispatcherQueue.EnqueueAsync(async () =>
+ {
+ Grid grid = CreateGrid(width, height);
+ await SetTestContentAsync(grid);
+ var trigger = new ControlSizeTrigger();
+
+ trigger.TargetElement = grid;
+ trigger.MaxHeight = 450;
+
+ Assert.AreEqual(expectedResult, trigger.IsActive);
+ });
+ }
+
+ [DataTestMethod]
+ [DataRow(450, 450, false)]
+ [DataRow(449, 450, true)]
+ public async Task ControlSizeMaxWidthTriggerTest(double width, double height, bool expectedResult)
+ {
+ await App.DispatcherQueue.EnqueueAsync(async () =>
+ {
+ Grid grid = CreateGrid(width, height);
+ await SetTestContentAsync(grid);
+ var trigger = new ControlSizeTrigger();
+
+ trigger.TargetElement = grid;
+ trigger.MaxWidth = 450;
+
+ Assert.AreEqual(expectedResult, trigger.IsActive);
+ });
+ }
+
+ private Grid CreateGrid(double width, double height)
+ {
+ var grid = new Grid()
+ {
+ Height = height,
+ Width = width
+ };
+
+ return grid;
+ }
+ }
+}
diff --git a/UnitTests/UnitTests.UWP/UnitTests.UWP.csproj b/UnitTests/UnitTests.UWP/UnitTests.UWP.csproj
index fef868d9e62..769f3737d85 100644
--- a/UnitTests/UnitTests.UWP/UnitTests.UWP.csproj
+++ b/UnitTests/UnitTests.UWP/UnitTests.UWP.csproj
@@ -255,6 +255,7 @@
+