Adding control size trigger (#3867)
<!-- 🚨 Please Do Not skip any instructions and information mentioned below as they are all required and essential to evaluate and test the PR. By fulfilling all the required information you will be able to reduce the volume of questions and most likely help merge the PR faster 🚨 --> <!-- 📝 It is preferred if you keep the "☑️ Allow edits by maintainers" checked in the Pull Request Template as it increases collaboration with the Toolkit maintainers by permitting commits to your PR branch (only) created from your fork. This can let us quickly make fixes for minor typos or forgotten StyleCop issues during review without needing to wait on you doing extra work. Let us help you help us! 🎉 --> ## Fixes # <!-- Add the relevant issue number after the "#" mentioned above (for ex: Fixes #1234) which will automatically close the issue once the PR is merged. --> <!-- Add a brief overview here of the feature/bug & fix. --> Adding a new visual state trigger which can be triggered based on a the width of a UI element rather than the width of the app's entire window. ## PR Type What kind of change does this PR introduce? <!-- Please uncomment one or more that apply to this PR. --> <!-- - Bugfix --> Feature <!-- - Code style update (formatting) --> <!-- - Refactoring (no functional changes, no api changes) --> <!-- - Build or CI related changes --> <!-- - Documentation content changes --> <!-- - Sample app changes --> <!-- - Other... Please describe: --> ## What is the current behavior? <!-- Please describe the current behavior that you are modifying, or link to a relevant issue. --> ## What is the new behavior? <!-- Describe how was this issue resolved or changed? --> ## PR Checklist Please check if your PR fulfills the following requirements: - [x] Tested code with current [supported SDKs](../readme.md#supported) - [x] Pull Request has been submitted to the documentation repository [instructions](..\contributing.md#docs). Link: https://github.com/MicrosoftDocs/WindowsCommunityToolkitDocs/pull/551<!-- docs PR link --> - [x] Sample in sample app has been added / updated (for bug fixes / features) - [x] Icon has been created (if new sample) following the [Thumbnail Style Guide and templates](https://github.com/windows-toolkit/WindowsCommunityToolkit-design-assets) - [x] New major technical changes in the toolkit have or will be added to the [Wiki](https://github.com/windows-toolkit/WindowsCommunityToolkit/wiki) e.g. build changes, source generators, testing infrastructure, sample creation changes, etc... - [x] Tests for the changes have been added (for bug fixes / features) (if applicable) - [x] Header has been added to all new source files (run *build/UpdateHeaders.bat*) - [x] Contains **NO** breaking changes <!-- If this PR contains a breaking change, please describe the impact and migration path for existing applications below. Please note that breaking changes are likely to be rejected within minor release cycles or held until major versions. --> ## Other information
This commit is contained in:
Коммит
d9e8845501
|
@ -1079,6 +1079,10 @@
|
|||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Content>
|
||||
<Content Include="SamplePages\Triggers\ControlSizeTrigger.bind">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Content>
|
||||
<Page Include="SamplePages\Triggers\FullScreenModeStateTriggerPage.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
|
|
|
@ -0,0 +1,43 @@
|
|||
<Page
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:triggers="using:Microsoft.Toolkit.Uwp.UI.Triggers"
|
||||
mc:Ignorable="d">
|
||||
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
|
||||
|
||||
<VisualStateManager.VisualStateGroups>
|
||||
<VisualStateGroup>
|
||||
<VisualState>
|
||||
<VisualState.StateTriggers>
|
||||
<triggers:ControlSizeTrigger
|
||||
TargetElement="{Binding ElementName=ParentGrid}"
|
||||
MinWidth="400"
|
||||
MaxWidth="500"/>
|
||||
</VisualState.StateTriggers>
|
||||
<VisualState.Setters>
|
||||
<Setter Target="ResizingText.FontSize" Value="20"/>
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
</VisualStateGroup>
|
||||
</VisualStateManager.VisualStateGroups>
|
||||
|
||||
<StackPanel VerticalAlignment="Center" Width="500">
|
||||
<Grid
|
||||
x:Name="ParentGrid"
|
||||
Width="{Binding Value, ElementName=Slider, Mode=OneWay}"
|
||||
Height="50"
|
||||
Background="Blue"/>
|
||||
<TextBlock
|
||||
x:Name="ResizingText"
|
||||
FontSize="12"
|
||||
Text="Windows Community Toolkit"
|
||||
HorizontalAlignment="Center"/>
|
||||
<Slider
|
||||
x:Name="Slider"
|
||||
Minimum="0"
|
||||
Maximum="500" />
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Page>
|
|
@ -31,6 +31,7 @@
|
|||
<triggers:RegexStateTrigger x:Key="RegexStateTrigger" />
|
||||
<triggers:UserHandPreferenceStateTrigger x:Key="UserHandPreferenceStateTrigger" />
|
||||
<triggers:UserInteractionModeStateTrigger x:Key="UserInteractionModeStateTrigger" />
|
||||
<triggers:ControlSizeTrigger x:Key="ControlSizeTrigger" />
|
||||
<behaviors:StartAnimationAction x:Key="StartAnimationAction" />
|
||||
<behaviors:KeyDownTriggerBehavior x:Key="KeyDownTriggerBehavior" />
|
||||
<behaviors:AutoSelectBehavior x:Key="AutoSelectBehavior" />
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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
|
||||
{
|
||||
/// <summary>
|
||||
/// A conditional state trigger that functions
|
||||
/// based on the target control's width or height.
|
||||
/// </summary>
|
||||
public class ControlSizeTrigger : StateTriggerBase
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating
|
||||
/// whether this trigger will be active or not.
|
||||
/// </summary>
|
||||
public bool CanTrigger
|
||||
{
|
||||
get => (bool)GetValue(CanTriggerProperty);
|
||||
set => SetValue(CanTriggerProperty, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Identifies the <see cref="CanTrigger"/> DependencyProperty.
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty CanTriggerProperty = DependencyProperty.Register(
|
||||
nameof(CanTrigger),
|
||||
typeof(bool),
|
||||
typeof(ControlSizeTrigger),
|
||||
new PropertyMetadata(true, (d, e) => ((ControlSizeTrigger)d).UpdateTrigger()));
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
public double MaxWidth
|
||||
{
|
||||
get => (double)GetValue(MaxWidthProperty);
|
||||
set => SetValue(MaxWidthProperty, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Identifies the <see cref="MaxWidth"/> DependencyProperty.
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty MaxWidthProperty = DependencyProperty.Register(
|
||||
nameof(MaxWidth),
|
||||
typeof(double),
|
||||
typeof(ControlSizeTrigger),
|
||||
new PropertyMetadata(double.PositiveInfinity, (d, e) => ((ControlSizeTrigger)d).UpdateTrigger()));
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
public double MinWidth
|
||||
{
|
||||
get => (double)GetValue(MinWidthProperty);
|
||||
set => SetValue(MinWidthProperty, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Identifies the <see cref="MinWidth"/> DependencyProperty.
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty MinWidthProperty = DependencyProperty.Register(
|
||||
nameof(MinWidth),
|
||||
typeof(double),
|
||||
typeof(ControlSizeTrigger),
|
||||
new PropertyMetadata(0.0, (d, e) => ((ControlSizeTrigger)d).UpdateTrigger()));
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
public double MaxHeight
|
||||
{
|
||||
get => (double)GetValue(MaxHeightProperty);
|
||||
set => SetValue(MaxHeightProperty, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Identifies the <see cref="MaxHeight"/> DependencyProperty.
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty MaxHeightProperty = DependencyProperty.Register(
|
||||
nameof(MaxHeight),
|
||||
typeof(double),
|
||||
typeof(ControlSizeTrigger),
|
||||
new PropertyMetadata(double.PositiveInfinity, (d, e) => ((ControlSizeTrigger)d).UpdateTrigger()));
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
public double MinHeight
|
||||
{
|
||||
get => (double)GetValue(MinHeightProperty);
|
||||
set => SetValue(MinHeightProperty, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Identifies the <see cref="MinHeight"/> DependencyProperty.
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty MinHeightProperty = DependencyProperty.Register(
|
||||
nameof(MinHeight),
|
||||
typeof(double),
|
||||
typeof(ControlSizeTrigger),
|
||||
new PropertyMetadata(0.0, (d, e) => ((ControlSizeTrigger)d).UpdateTrigger()));
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the element whose width will observed
|
||||
/// for the trigger.
|
||||
/// </summary>
|
||||
public FrameworkElement TargetElement
|
||||
{
|
||||
get => (FrameworkElement)GetValue(TargetElementProperty);
|
||||
set => SetValue(TargetElementProperty, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Identifies the <see cref="TargetElement"/> DependencyProperty.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Using a DependencyProperty as the backing store for TargetElement. This enables animation, styling, binding, etc.
|
||||
/// </remarks>
|
||||
public static readonly DependencyProperty TargetElementProperty = DependencyProperty.Register(
|
||||
nameof(TargetElement),
|
||||
typeof(FrameworkElement),
|
||||
typeof(ControlSizeTrigger),
|
||||
new PropertyMetadata(null, OnTargetElementPropertyChanged));
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the trigger is active.
|
||||
/// </summary>
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -255,6 +255,7 @@
|
|||
<Compile Include="UI\Extensions\Test_VisualExtensions.cs" />
|
||||
<Compile Include="UI\Person.cs" />
|
||||
<Compile Include="UI\Test_AdvancedCollectionView.cs" />
|
||||
<Compile Include="UI\Triggers\Test_ControlSizeTrigger.cs" />
|
||||
<Compile Include="VisualUITestBase.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
|
Загрузка…
Ссылка в новой задаче