From 76c947d409f15ae284a1ba6786586616b5d9b41d Mon Sep 17 00:00:00 2001 From: michael-hawker <24302614+michael-hawker@users.noreply.github.com> Date: Thu, 30 Jul 2020 13:29:59 -0700 Subject: [PATCH 01/22] Initial Commit of ContentSizer Content Sizer Issues: - [ ] TargetControl isn't loaded yet causes problems (Expander Issue) - [ ] Size Direction needs to be more specific (only works Left/Top, not Right/Bottom) - [ ] Do we support 'Auto'? - [ ] Need to set Automation Property Name in Code-Behind - [ ] Content Initial value as binding converter to ResizeDirection? --- .../Microsoft.Toolkit.Uwp.SampleApp.csproj | 11 +- .../ContentSizer/ContentSizer.bind | 48 +++++ .../SamplePages/ContentSizer/ContentSizer.png | Bin 0 -> 850 bytes .../ContentSizer/ContentSizerPage.xaml | 11 ++ .../ContentSizer/ContentSizerPage.xaml.cs | 18 ++ .../SamplePages/samples.json | 10 ++ .../ContentSizer/ContentResizeDirection.cs | 28 +++ .../ContentSizer/ContentSizer.Events.cs | 169 ++++++++++++++++++ .../ContentSizer/ContentSizer.Properties.cs | 129 +++++++++++++ .../ContentSizer/ContentSizer.cs | 50 ++++++ .../ContentSizer/ContentSizer.xaml | 41 +++++ .../Strings/en-US/Resources.resw | 4 + .../Themes/Generic.xaml | 1 + 13 files changed, 519 insertions(+), 1 deletion(-) create mode 100644 Microsoft.Toolkit.Uwp.SampleApp/SamplePages/ContentSizer/ContentSizer.bind create mode 100644 Microsoft.Toolkit.Uwp.SampleApp/SamplePages/ContentSizer/ContentSizer.png create mode 100644 Microsoft.Toolkit.Uwp.SampleApp/SamplePages/ContentSizer/ContentSizerPage.xaml create mode 100644 Microsoft.Toolkit.Uwp.SampleApp/SamplePages/ContentSizer/ContentSizerPage.xaml.cs create mode 100644 Microsoft.Toolkit.Uwp.UI.Controls.Layout/ContentSizer/ContentResizeDirection.cs create mode 100644 Microsoft.Toolkit.Uwp.UI.Controls.Layout/ContentSizer/ContentSizer.Events.cs create mode 100644 Microsoft.Toolkit.Uwp.UI.Controls.Layout/ContentSizer/ContentSizer.Properties.cs create mode 100644 Microsoft.Toolkit.Uwp.UI.Controls.Layout/ContentSizer/ContentSizer.cs create mode 100644 Microsoft.Toolkit.Uwp.UI.Controls.Layout/ContentSizer/ContentSizer.xaml diff --git a/Microsoft.Toolkit.Uwp.SampleApp/Microsoft.Toolkit.Uwp.SampleApp.csproj b/Microsoft.Toolkit.Uwp.SampleApp/Microsoft.Toolkit.Uwp.SampleApp.csproj index 2018763e733..4edc836d344 100644 --- a/Microsoft.Toolkit.Uwp.SampleApp/Microsoft.Toolkit.Uwp.SampleApp.csproj +++ b/Microsoft.Toolkit.Uwp.SampleApp/Microsoft.Toolkit.Uwp.SampleApp.csproj @@ -273,6 +273,7 @@ + PreserveNewest @@ -496,6 +497,9 @@ + + ContentSizerPage.xaml + AutoFocusBehaviorPage.xaml @@ -607,6 +611,7 @@ + @@ -973,6 +978,10 @@ Designer MSBuild:Compile + + MSBuild:Compile + Designer + Designer MSBuild:Compile @@ -1565,4 +1574,4 @@ - \ No newline at end of file + diff --git a/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/ContentSizer/ContentSizer.bind b/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/ContentSizer/ContentSizer.bind new file mode 100644 index 00000000000..b19fec6605f --- /dev/null +++ b/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/ContentSizer/ContentSizer.bind @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + Side Content + + + + + + + + + + + + + + diff --git a/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/ContentSizer/ContentSizer.png b/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/ContentSizer/ContentSizer.png new file mode 100644 index 0000000000000000000000000000000000000000..004cf329744e43b63db15f3f514c5db4b3ed58a7 GIT binary patch literal 850 zcmeAS@N?(olHy`uVBq!ia0y~yU{nCI4{)#n$t4^1Z39w_#X;^)4C~IxyaaMs(j9#r z85lP9bN@+X1@buyJR*x382Ao@Fyrz36)6l1OwT=C978JN-rhNw+Z-U^;5bKZMFZ0u zt{ASRJ4Cd+m_r`uIqB4#?$p@hF>_+rt$MerM_Z;RO02uhFz21yjc4#v zcW`iPXy{>Jlw@QwVq!^Q;W)t|FhNj3K^aY=uBI<}-t+$2rwyr*$7=sxGx7CX`XPPo z>tFlUyIUM*EWxR9*hswS-*Nx_;kRYg=dSbpZzLRIdbeY?SK7q0pZWY}<9eA5I;VH6 zzdvi)%MaTd?{8c8`u9FL!(Yt!!+cl--Spgbw{7O>H+=5-M^r+Cc)D`#V+M + + + + diff --git a/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/ContentSizer/ContentSizerPage.xaml.cs b/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/ContentSizer/ContentSizerPage.xaml.cs new file mode 100644 index 00000000000..b1cd281bead --- /dev/null +++ b/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/ContentSizer/ContentSizerPage.xaml.cs @@ -0,0 +1,18 @@ +// 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 Microsoft.Toolkit.Uwp.SampleApp.Models; +using Windows.UI.Xaml.Controls; +using Windows.UI.Xaml.Navigation; + +namespace Microsoft.Toolkit.Uwp.SampleApp.SamplePages +{ + public sealed partial class ContentSizerPage : Page + { + public ContentSizerPage() + { + InitializeComponent(); + } + } +} diff --git a/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/samples.json b/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/samples.json index 8cdfcc3a619..29cc5b41e66 100644 --- a/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/samples.json +++ b/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/samples.json @@ -175,6 +175,16 @@ "Icon": "/SamplePages/ScrollHeader/ScrollHeader.png", "DocumentationUrl": "https://raw.githubusercontent.com/MicrosoftDocs/WindowsCommunityToolkitDocs/master/docs/behaviors/HeaderBehaviors.md" }, + { + "Name": "ContentSizer", + "Type": "ContentSizerPage", + "Subcategory": "Layout", + "About": "ContentSizer is a general sizing control which can manipulate the size of its parent or other elements. Used as a building block for more complex UI systems.", + "CodeUrl": "https://github.com/windows-toolkit/WindowsCommunityToolkit/tree/main/Microsoft.Toolkit.Uwp.UI.Controls.Layout/ContentSizer", + "XamlCodeFile": "ContentSizer.bind", + "Icon": "/SamplePages/ContentSizer/ContentSizer.png", + "DocumentationUrl": "https://raw.githubusercontent.com/MicrosoftDocs/WindowsCommunityToolkitDocs/master/docs/controls/ContentSizer.md" + }, { "Name": "GridSplitter", "Type": "GridSplitterPage", diff --git a/Microsoft.Toolkit.Uwp.UI.Controls.Layout/ContentSizer/ContentResizeDirection.cs b/Microsoft.Toolkit.Uwp.UI.Controls.Layout/ContentSizer/ContentResizeDirection.cs new file mode 100644 index 00000000000..810769aaed3 --- /dev/null +++ b/Microsoft.Toolkit.Uwp.UI.Controls.Layout/ContentSizer/ContentResizeDirection.cs @@ -0,0 +1,28 @@ +// 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. + +namespace Microsoft.Toolkit.Uwp.UI.Controls +{ + /// + /// Enum to indicate whether resizes Vertically or Horizontally. + /// + public enum ContentResizeDirection + { + /// + /// Determines whether to resize rows or columns based on its Alignment and + /// width compared to height + /// + Auto, // TODO: Detect? + + /// + /// Resize columns when dragging Splitter. + /// + Vertical, + + /// + /// Resize rows when dragging Splitter. + /// + Horizontal + } +} diff --git a/Microsoft.Toolkit.Uwp.UI.Controls.Layout/ContentSizer/ContentSizer.Events.cs b/Microsoft.Toolkit.Uwp.UI.Controls.Layout/ContentSizer/ContentSizer.Events.cs new file mode 100644 index 00000000000..3ce502e5d71 --- /dev/null +++ b/Microsoft.Toolkit.Uwp.UI.Controls.Layout/ContentSizer/ContentSizer.Events.cs @@ -0,0 +1,169 @@ +// 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 Microsoft.Toolkit.Uwp.UI; +using Windows.UI.Xaml; +using Windows.UI.Xaml.Controls; +using Windows.UI.Xaml.Input; + +namespace Microsoft.Toolkit.Uwp.UI.Controls +{ + /// + /// Events for . + /// + public partial class ContentSizer + { + // If no values specified, setup our default behaviors. + private void ContentSizer_Loaded(object sender, RoutedEventArgs e) + { + // Adding Grip to Grid Splitter + if (Content == null) + { + // TODO: Make Converter to put in XAML? + Content = + ResizeDirection == ContentResizeDirection.Vertical ? GripperBarVertical : GripperBarHorizontal; + } + + if (TargetControl == null) + { + TargetControl = this.FindAscendant(); + } + } + + private void ContentSizer_KeyUp(object sender, KeyRoutedEventArgs e) + { + if (ResizeDirection == ContentResizeDirection.Vertical) + { + if (e.Key == Windows.System.VirtualKey.Left) + { + HorizontalMove(-GripperKeyboardChange); + } + else if (e.Key == Windows.System.VirtualKey.Right) + { + HorizontalMove(GripperKeyboardChange); + } + } + else + { + if (e.Key == Windows.System.VirtualKey.Up) + { + VerticalMove(-GripperKeyboardChange); + } + else if (e.Key == Windows.System.VirtualKey.Down) + { + VerticalMove(GripperKeyboardChange); + } + } + } + + /// + protected override void OnManipulationDelta(ManipulationDeltaRoutedEventArgs e) + { + var horizontalChange = e.Delta.Translation.X; + var verticalChange = e.Delta.Translation.Y; + + if (ResizeDirection == ContentResizeDirection.Vertical) + { + if (HorizontalMove(horizontalChange)) + { + return; + } + } + else if (ResizeDirection == ContentResizeDirection.Horizontal) + { + if (VerticalMove(verticalChange)) + { + return; + } + } + + base.OnManipulationDelta(e); + } + + private bool VerticalMove(double verticalChange) + { + if (TargetControl == null) + { + return true; + } + + if (!IsValidHeight(TargetControl, verticalChange)) + { + return true; + } + + // TODO: This only works if splitter is on top and making things grow down + // Do we need our ContentResizeDirection to be 4 way? Maybe 'Auto' would check the horizontal/vertical alignment of the target??? + TargetControl.Height += verticalChange; + + return false; + } + + private bool HorizontalMove(double horizontalChange) + { + if (TargetControl == null) + { + return true; + } + + if (!IsValidWidth(TargetControl, horizontalChange)) + { + return true; + } + + // TODO: This only works if splitter is on left and making things grow right... + TargetControl.Width += horizontalChange; + + return false; + } + + private bool IsValidHeight(FrameworkElement target, double verticalChange) + { + var newHeight = target.ActualHeight + verticalChange; + + var minHeight = target.MinHeight; + if (newHeight < 0 || (!double.IsNaN(minHeight) && newHeight < minHeight)) + { + return false; + } + + var maxHeight = target.MaxHeight; + if (!double.IsNaN(maxHeight) && newHeight > maxHeight) + { + return false; + } + + if (newHeight <= ActualHeight) + { + return false; + } + + return true; + } + + private bool IsValidWidth(FrameworkElement target, double horizontalChange) + { + var newWidth = target.ActualWidth + horizontalChange; + + var minWidth = target.MinWidth; + if (newWidth < 0 || (!double.IsNaN(minWidth) && newWidth < minWidth)) + { + return false; + } + + var maxWidth = target.MaxWidth; + if (!double.IsNaN(maxWidth) && newWidth > maxWidth) + { + return false; + } + + if (newWidth <= ActualWidth) + { + return false; + } + + return true; + } + } +} diff --git a/Microsoft.Toolkit.Uwp.UI.Controls.Layout/ContentSizer/ContentSizer.Properties.cs b/Microsoft.Toolkit.Uwp.UI.Controls.Layout/ContentSizer/ContentSizer.Properties.cs new file mode 100644 index 00000000000..09504766ad4 --- /dev/null +++ b/Microsoft.Toolkit.Uwp.UI.Controls.Layout/ContentSizer/ContentSizer.Properties.cs @@ -0,0 +1,129 @@ +// 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 System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Windows.UI.Core; +using Windows.UI.Xaml; +using Windows.UI.Xaml.Media; + +namespace Microsoft.Toolkit.Uwp.UI.Controls +{ + /// + /// Properties of the control. + /// + public partial class ContentSizer + { + /// + /// Gets or sets the content of the sizer, by default is the grip symbol. + /// + public object Content + { + get { return (object)GetValue(ContentProperty); } + set { SetValue(ContentProperty, value); } + } + + /// + /// Identifies the dependency property. + /// + public static readonly DependencyProperty ContentProperty = + DependencyProperty.Register(nameof(Content), typeof(object), typeof(ContentSizer), new PropertyMetadata(null)); + + /// + /// Gets or sets the content template for the . By default is a TextBlock. + /// + public DataTemplate ContentTemplate + { + get { return (DataTemplate)GetValue(ContentTemplateProperty); } + set { SetValue(ContentTemplateProperty, value); } + } + + /// + /// Identifies the dependency property. + /// + public static readonly DependencyProperty ContentTemplateProperty = + DependencyProperty.Register(nameof(ContentTemplate), typeof(DataTemplate), typeof(ContentSizer), new PropertyMetadata(null)); + + /// + /// Gets or sets the cursor to use when hovering over the sizer. + /// + public CoreCursorType GripperCursor + { + get { return (CoreCursorType)GetValue(GripperCursorProperty); } + set { SetValue(GripperCursorProperty, value); } + } + + /// + /// Identifies the dependency property. + /// + public static readonly DependencyProperty GripperCursorProperty = + DependencyProperty.Register(nameof(GripperCursor), typeof(CoreCursorType), typeof(ContentSizer), new PropertyMetadata(CoreCursorType.SizeWestEast)); + + /// + /// Gets or sets the foreground color of sizer grip. + /// + public Brush GripperForeground + { + get { return (Brush)GetValue(GripperForegroundProperty); } + set { SetValue(GripperForegroundProperty, value); } + } + + /// + /// Identifies the dependency property. + /// + public static readonly DependencyProperty GripperForegroundProperty = + DependencyProperty.Register(nameof(GripperForeground), typeof(Brush), typeof(ContentSizer), new PropertyMetadata(default(Brush))); + + /// + /// Gets or sets the direction that the sizer will interact with. + /// + public ContentResizeDirection ResizeDirection + { + get { return (ContentResizeDirection)GetValue(ResizeDirectionProperty); } + set { SetValue(ResizeDirectionProperty, value); } + } + + /// + /// Identifies the dependency property. + /// + public static readonly DependencyProperty ResizeDirectionProperty = + DependencyProperty.Register(nameof(ResizeDirection), typeof(ContentResizeDirection), typeof(ContentSizer), new PropertyMetadata(ContentResizeDirection.Vertical)); + + /// + /// Gets or sets the control that the is resizing. Be default, this will be the visual ancestor of the . + /// + public FrameworkElement TargetControl + { + get { return (FrameworkElement)GetValue(TargetControlProperty); } + set { SetValue(TargetControlProperty, value); } + } + + /// + /// Identifies the dependency property. + /// + public static readonly DependencyProperty TargetControlProperty = + DependencyProperty.Register(nameof(TargetControl), typeof(FrameworkElement), typeof(ContentSizer), new PropertyMetadata(null, OnTargetControlChanged)); + + private static void OnTargetControlChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + // Check if our width can be manipulated + if (d is ContentSizer sizer && e.NewValue is FrameworkElement element) + { + // TODO: For Auto we might want to do detection logic (TBD) here first? + if (sizer.ResizeDirection != ContentResizeDirection.Horizontal && double.IsNaN(element.Width)) + { + element.Width = element.DesiredSize.Width; + } + + if (sizer.ResizeDirection != ContentResizeDirection.Vertical && double.IsNaN(element.Height)) + { + element.Height = element.DesiredSize.Height; + } + } + } + } +} diff --git a/Microsoft.Toolkit.Uwp.UI.Controls.Layout/ContentSizer/ContentSizer.cs b/Microsoft.Toolkit.Uwp.UI.Controls.Layout/ContentSizer/ContentSizer.cs new file mode 100644 index 00000000000..ad4927b4d35 --- /dev/null +++ b/Microsoft.Toolkit.Uwp.UI.Controls.Layout/ContentSizer/ContentSizer.cs @@ -0,0 +1,50 @@ +// 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.Controls; +using Windows.UI.Xaml.Input; +using Windows.UI.Xaml.Markup; + +namespace Microsoft.Toolkit.Uwp.UI.Controls +{ + /// + /// The is a control which can be used to resize any element, usually its parent. If you are using a , use instead. + /// + [ContentProperty(Name = nameof(Content))] + public partial class ContentSizer : Control + { + // Symbols for GripperBar in Segoe MDL2 Assets + private const string GripperBarVertical = "\xE784"; + private const string GripperBarHorizontal = "\xE76F"; + + private const double GripperKeyboardChange = 8.0d; + + /// + /// Initializes a new instance of the class. + /// + public ContentSizer() + { + this.DefaultStyleKey = typeof(ContentSizer); + + // TODO: Can this be set in XAML, do we open a WinUI issue to track? + ManipulationMode = ManipulationModes.TranslateX | ManipulationModes.TranslateY; + + KeyUp += ContentSizer_KeyUp; + } + + /// + protected override void OnApplyTemplate() + { + base.OnApplyTemplate(); + + // Note, we re-register for the proper timing to check for default property values. If we just set Loaded once in our constructor this doesn't work... Not sure why... 🤷‍ + + // Unhook registered events + Loaded -= ContentSizer_Loaded; + + // Register Events + Loaded += ContentSizer_Loaded; + } + } +} diff --git a/Microsoft.Toolkit.Uwp.UI.Controls.Layout/ContentSizer/ContentSizer.xaml b/Microsoft.Toolkit.Uwp.UI.Controls.Layout/ContentSizer/ContentSizer.xaml new file mode 100644 index 00000000000..d5067a6fb89 --- /dev/null +++ b/Microsoft.Toolkit.Uwp.UI.Controls.Layout/ContentSizer/ContentSizer.xaml @@ -0,0 +1,41 @@ + + + + diff --git a/Microsoft.Toolkit.Uwp.UI.Controls.Layout/Strings/en-US/Resources.resw b/Microsoft.Toolkit.Uwp.UI.Controls.Layout/Strings/en-US/Resources.resw index 49a13464e39..3593b3964d4 100644 --- a/Microsoft.Toolkit.Uwp.UI.Controls.Layout/Strings/en-US/Resources.resw +++ b/Microsoft.Toolkit.Uwp.UI.Controls.Layout/Strings/en-US/Resources.resw @@ -69,4 +69,8 @@ GridSplitter Narrator Resource for GridSplitter control + + Content Sizer + Narrator Resource for ContentSizer control + \ No newline at end of file diff --git a/Microsoft.Toolkit.Uwp.UI.Controls.Layout/Themes/Generic.xaml b/Microsoft.Toolkit.Uwp.UI.Controls.Layout/Themes/Generic.xaml index fd84465abdd..0dd0bd41c94 100644 --- a/Microsoft.Toolkit.Uwp.UI.Controls.Layout/Themes/Generic.xaml +++ b/Microsoft.Toolkit.Uwp.UI.Controls.Layout/Themes/Generic.xaml @@ -3,6 +3,7 @@ + From cfc2c5782ae564b6650e757557f39bdaaec785ff Mon Sep 17 00:00:00 2001 From: michael-hawker <24302614+michael-hawker@users.noreply.github.com> Date: Tue, 15 Jun 2021 15:39:49 -0700 Subject: [PATCH 02/22] Remove backing page from ContentSizer samples Bonus also fixes issue with sample loading the first time... --- .../Microsoft.Toolkit.Uwp.SampleApp.csproj | 7 ------- .../ContentSizer/ContentSizerPage.xaml | 11 ----------- .../ContentSizer/ContentSizerPage.xaml.cs | 18 ------------------ .../SamplePages/XamlOnlyPage.xaml | 1 + .../SamplePages/samples.json | 3 +-- 5 files changed, 2 insertions(+), 38 deletions(-) delete mode 100644 Microsoft.Toolkit.Uwp.SampleApp/SamplePages/ContentSizer/ContentSizerPage.xaml delete mode 100644 Microsoft.Toolkit.Uwp.SampleApp/SamplePages/ContentSizer/ContentSizerPage.xaml.cs diff --git a/Microsoft.Toolkit.Uwp.SampleApp/Microsoft.Toolkit.Uwp.SampleApp.csproj b/Microsoft.Toolkit.Uwp.SampleApp/Microsoft.Toolkit.Uwp.SampleApp.csproj index 4edc836d344..15a32095f9b 100644 --- a/Microsoft.Toolkit.Uwp.SampleApp/Microsoft.Toolkit.Uwp.SampleApp.csproj +++ b/Microsoft.Toolkit.Uwp.SampleApp/Microsoft.Toolkit.Uwp.SampleApp.csproj @@ -497,9 +497,6 @@ - - ContentSizerPage.xaml - AutoFocusBehaviorPage.xaml @@ -978,10 +975,6 @@ Designer MSBuild:Compile - - MSBuild:Compile - Designer - Designer MSBuild:Compile diff --git a/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/ContentSizer/ContentSizerPage.xaml b/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/ContentSizer/ContentSizerPage.xaml deleted file mode 100644 index 85dd275bab3..00000000000 --- a/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/ContentSizer/ContentSizerPage.xaml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - diff --git a/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/ContentSizer/ContentSizerPage.xaml.cs b/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/ContentSizer/ContentSizerPage.xaml.cs deleted file mode 100644 index b1cd281bead..00000000000 --- a/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/ContentSizer/ContentSizerPage.xaml.cs +++ /dev/null @@ -1,18 +0,0 @@ -// 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 Microsoft.Toolkit.Uwp.SampleApp.Models; -using Windows.UI.Xaml.Controls; -using Windows.UI.Xaml.Navigation; - -namespace Microsoft.Toolkit.Uwp.SampleApp.SamplePages -{ - public sealed partial class ContentSizerPage : Page - { - public ContentSizerPage() - { - InitializeComponent(); - } - } -} diff --git a/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/XamlOnlyPage.xaml b/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/XamlOnlyPage.xaml index a4187d65e0a..694fb69707f 100644 --- a/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/XamlOnlyPage.xaml +++ b/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/XamlOnlyPage.xaml @@ -50,6 +50,7 @@ + diff --git a/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/samples.json b/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/samples.json index 29cc5b41e66..73610fa2068 100644 --- a/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/samples.json +++ b/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/samples.json @@ -177,11 +177,10 @@ }, { "Name": "ContentSizer", - "Type": "ContentSizerPage", "Subcategory": "Layout", "About": "ContentSizer is a general sizing control which can manipulate the size of its parent or other elements. Used as a building block for more complex UI systems.", "CodeUrl": "https://github.com/windows-toolkit/WindowsCommunityToolkit/tree/main/Microsoft.Toolkit.Uwp.UI.Controls.Layout/ContentSizer", - "XamlCodeFile": "ContentSizer.bind", + "XamlCodeFile": "/SamplePages/ContentSizer/ContentSizer.bind", "Icon": "/SamplePages/ContentSizer/ContentSizer.png", "DocumentationUrl": "https://raw.githubusercontent.com/MicrosoftDocs/WindowsCommunityToolkitDocs/master/docs/controls/ContentSizer.md" }, From 4f18bc9c59a09047e421de8edb2bf2783a2bc9ad Mon Sep 17 00:00:00 2001 From: Darren Batchelor Date: Wed, 29 Dec 2021 16:48:52 -0800 Subject: [PATCH 03/22] init commit --- .../ContentSizer/ContentSizer.Properties.cs | 79 +--------- .../ContentSizer/ContentSizer.cs | 4 +- .../GridSplitter/GridSplitter.Options.cs | 32 ++--- .../GridSplitter/GridSplitter.cs | 2 +- .../GridSplitter/SplitBase.cs | 136 ++++++++++++++++++ 5 files changed, 156 insertions(+), 97 deletions(-) create mode 100644 Microsoft.Toolkit.Uwp.UI.Controls.Layout/GridSplitter/SplitBase.cs diff --git a/Microsoft.Toolkit.Uwp.UI.Controls.Layout/ContentSizer/ContentSizer.Properties.cs b/Microsoft.Toolkit.Uwp.UI.Controls.Layout/ContentSizer/ContentSizer.Properties.cs index 09504766ad4..7e400935841 100644 --- a/Microsoft.Toolkit.Uwp.UI.Controls.Layout/ContentSizer/ContentSizer.Properties.cs +++ b/Microsoft.Toolkit.Uwp.UI.Controls.Layout/ContentSizer/ContentSizer.Properties.cs @@ -1,4 +1,4 @@ -// Licensed to the .NET Foundation under one or more agreements. +// 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. @@ -18,21 +18,6 @@ namespace Microsoft.Toolkit.Uwp.UI.Controls /// public partial class ContentSizer { - /// - /// Gets or sets the content of the sizer, by default is the grip symbol. - /// - public object Content - { - get { return (object)GetValue(ContentProperty); } - set { SetValue(ContentProperty, value); } - } - - /// - /// Identifies the dependency property. - /// - public static readonly DependencyProperty ContentProperty = - DependencyProperty.Register(nameof(Content), typeof(object), typeof(ContentSizer), new PropertyMetadata(null)); - /// /// Gets or sets the content template for the . By default is a TextBlock. /// @@ -48,21 +33,6 @@ public DataTemplate ContentTemplate public static readonly DependencyProperty ContentTemplateProperty = DependencyProperty.Register(nameof(ContentTemplate), typeof(DataTemplate), typeof(ContentSizer), new PropertyMetadata(null)); - /// - /// Gets or sets the cursor to use when hovering over the sizer. - /// - public CoreCursorType GripperCursor - { - get { return (CoreCursorType)GetValue(GripperCursorProperty); } - set { SetValue(GripperCursorProperty, value); } - } - - /// - /// Identifies the dependency property. - /// - public static readonly DependencyProperty GripperCursorProperty = - DependencyProperty.Register(nameof(GripperCursor), typeof(CoreCursorType), typeof(ContentSizer), new PropertyMetadata(CoreCursorType.SizeWestEast)); - /// /// Gets or sets the foreground color of sizer grip. /// @@ -78,52 +48,5 @@ public Brush GripperForeground public static readonly DependencyProperty GripperForegroundProperty = DependencyProperty.Register(nameof(GripperForeground), typeof(Brush), typeof(ContentSizer), new PropertyMetadata(default(Brush))); - /// - /// Gets or sets the direction that the sizer will interact with. - /// - public ContentResizeDirection ResizeDirection - { - get { return (ContentResizeDirection)GetValue(ResizeDirectionProperty); } - set { SetValue(ResizeDirectionProperty, value); } - } - - /// - /// Identifies the dependency property. - /// - public static readonly DependencyProperty ResizeDirectionProperty = - DependencyProperty.Register(nameof(ResizeDirection), typeof(ContentResizeDirection), typeof(ContentSizer), new PropertyMetadata(ContentResizeDirection.Vertical)); - - /// - /// Gets or sets the control that the is resizing. Be default, this will be the visual ancestor of the . - /// - public FrameworkElement TargetControl - { - get { return (FrameworkElement)GetValue(TargetControlProperty); } - set { SetValue(TargetControlProperty, value); } - } - - /// - /// Identifies the dependency property. - /// - public static readonly DependencyProperty TargetControlProperty = - DependencyProperty.Register(nameof(TargetControl), typeof(FrameworkElement), typeof(ContentSizer), new PropertyMetadata(null, OnTargetControlChanged)); - - private static void OnTargetControlChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - // Check if our width can be manipulated - if (d is ContentSizer sizer && e.NewValue is FrameworkElement element) - { - // TODO: For Auto we might want to do detection logic (TBD) here first? - if (sizer.ResizeDirection != ContentResizeDirection.Horizontal && double.IsNaN(element.Width)) - { - element.Width = element.DesiredSize.Width; - } - - if (sizer.ResizeDirection != ContentResizeDirection.Vertical && double.IsNaN(element.Height)) - { - element.Height = element.DesiredSize.Height; - } - } - } } } diff --git a/Microsoft.Toolkit.Uwp.UI.Controls.Layout/ContentSizer/ContentSizer.cs b/Microsoft.Toolkit.Uwp.UI.Controls.Layout/ContentSizer/ContentSizer.cs index ad4927b4d35..6d040c63ee6 100644 --- a/Microsoft.Toolkit.Uwp.UI.Controls.Layout/ContentSizer/ContentSizer.cs +++ b/Microsoft.Toolkit.Uwp.UI.Controls.Layout/ContentSizer/ContentSizer.cs @@ -1,4 +1,4 @@ -// Licensed to the .NET Foundation under one or more agreements. +// 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. @@ -12,7 +12,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Controls /// The is a control which can be used to resize any element, usually its parent. If you are using a , use instead. /// [ContentProperty(Name = nameof(Content))] - public partial class ContentSizer : Control + public partial class ContentSizer : SplitBase { // Symbols for GripperBar in Segoe MDL2 Assets private const string GripperBarVertical = "\xE784"; diff --git a/Microsoft.Toolkit.Uwp.UI.Controls.Layout/GridSplitter/GridSplitter.Options.cs b/Microsoft.Toolkit.Uwp.UI.Controls.Layout/GridSplitter/GridSplitter.Options.cs index 5564c0336c7..177536f16a0 100644 --- a/Microsoft.Toolkit.Uwp.UI.Controls.Layout/GridSplitter/GridSplitter.Options.cs +++ b/Microsoft.Toolkit.Uwp.UI.Controls.Layout/GridSplitter/GridSplitter.Options.cs @@ -35,14 +35,14 @@ public static readonly DependencyProperty ResizeDirectionProperty new PropertyMetadata(GridResizeDirection.Auto)); /// - /// Identifies the dependency property. - /// - public static readonly DependencyProperty ResizeBehaviorProperty - = DependencyProperty.Register( - nameof(ResizeBehavior), - typeof(GridResizeBehavior), - typeof(GridSplitter), - new PropertyMetadata(GridResizeBehavior.BasedOnAlignment)); + ///// Identifies the dependency property. + ///// + //public static readonly DependencyProperty ResizeBehaviorProperty + // = DependencyProperty.Register( + // nameof(ResizeBehavior), + // typeof(GridResizeBehavior), + // typeof(GridSplitter), + // new PropertyMetadata(GridResizeBehavior.BasedOnAlignment)); /// /// Identifies the dependency property. @@ -113,15 +113,15 @@ public GridResizeDirection ResizeDirection set { SetValue(ResizeDirectionProperty, value); } } - /// - /// Gets or sets which Columns or Rows the Splitter resizes. - /// - public GridResizeBehavior ResizeBehavior - { - get { return (GridResizeBehavior)GetValue(ResizeBehaviorProperty); } + ///// + ///// Gets or sets which Columns or Rows the Splitter resizes. + ///// + //public GridResizeBehavior ResizeBehavior + //{ + // get { return (GridResizeBehavior)GetValue(ResizeBehaviorProperty); } - set { SetValue(ResizeBehaviorProperty, value); } - } + // set { SetValue(ResizeBehaviorProperty, value); } + //} /// /// Gets or sets the foreground color of grid splitter grip diff --git a/Microsoft.Toolkit.Uwp.UI.Controls.Layout/GridSplitter/GridSplitter.cs b/Microsoft.Toolkit.Uwp.UI.Controls.Layout/GridSplitter/GridSplitter.cs index c6f807397aa..b53cda9c7d1 100644 --- a/Microsoft.Toolkit.Uwp.UI.Controls.Layout/GridSplitter/GridSplitter.cs +++ b/Microsoft.Toolkit.Uwp.UI.Controls.Layout/GridSplitter/GridSplitter.cs @@ -33,7 +33,7 @@ public partial class GridSplitter : Control /// /// Gets the target parent grid from level /// - private FrameworkElement TargetControl + private new FrameworkElement TargetControl { get { diff --git a/Microsoft.Toolkit.Uwp.UI.Controls.Layout/GridSplitter/SplitBase.cs b/Microsoft.Toolkit.Uwp.UI.Controls.Layout/GridSplitter/SplitBase.cs new file mode 100644 index 00000000000..4090d829f33 --- /dev/null +++ b/Microsoft.Toolkit.Uwp.UI.Controls.Layout/GridSplitter/SplitBase.cs @@ -0,0 +1,136 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Windows.UI.Core; +using Windows.UI.Xaml; +using Windows.UI.Xaml.Controls; + +namespace Microsoft.Toolkit.Uwp.UI.Controls +{ + public partial class SplitBase : Control + { + /// + /// Gets or sets the content of the sizer, by default is the grip symbol. + /// + public object Content + { + get { return (object)GetValue(ContentProperty); } + set { SetValue(ContentProperty, value); } + } + + /// + /// Identifies the dependency property. + /// + public static readonly DependencyProperty ContentProperty = + DependencyProperty.Register(nameof(Content), typeof(object), typeof(SplitBase), new PropertyMetadata(null)); + + /// + /// Gets or sets the cursor to use when hovering over the sizer. + /// + public CoreCursorType GripperCursor + { + get { return (CoreCursorType)GetValue(GripperCursorProperty); } + set { SetValue(GripperCursorProperty, value); } + } + + /// + /// Identifies the dependency property. + /// + public static readonly DependencyProperty GripperCursorProperty = + DependencyProperty.Register(nameof(GripperCursor), typeof(CoreCursorType), typeof(SplitBase), new PropertyMetadata(CoreCursorType.SizeWestEast)); + + /// + /// Gets or sets the direction that the sizer will interact with. + /// + public ContentResizeDirection ResizeDirection + { + get { return (ContentResizeDirection)GetValue(ResizeDirectionProperty); } + set { SetValue(ResizeDirectionProperty, value); } + } + + /// + /// Identifies the dependency property. + /// + public static readonly DependencyProperty ResizeDirectionProperty = + DependencyProperty.Register(nameof(ResizeDirection), typeof(ContentResizeDirection), typeof(SplitBase), new PropertyMetadata(ContentResizeDirection.Vertical)); + + /// + /// Gets or sets the control that the is resizing. Be default, this will be the visual ancestor of the . + /// + public FrameworkElement TargetControl + { + get { return (FrameworkElement)GetValue(TargetControlProperty); } + set { SetValue(TargetControlProperty, value); } + } + + /// + /// Identifies the dependency property. + /// + public static readonly DependencyProperty TargetControlProperty = + DependencyProperty.Register(nameof(TargetControl), typeof(FrameworkElement), typeof(SplitBase), new PropertyMetadata(null, OnTargetControlChanged)); + + private static void OnTargetControlChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + // Check if our width can be manipulated + if (d is ContentSizer sizer && e.NewValue is FrameworkElement element) + { + // TODO: For Auto we might want to do detection logic (TBD) here first? + if (sizer.ResizeDirection != ContentResizeDirection.Horizontal && double.IsNaN(element.Width)) + { + element.Width = element.DesiredSize.Width; + } + + if (sizer.ResizeDirection != ContentResizeDirection.Vertical && double.IsNaN(element.Height)) + { + element.Height = element.DesiredSize.Height; + } + } + } + + /// Identifies the dependency property. + /// + public static readonly DependencyProperty ResizeBehaviorProperty + = DependencyProperty.Register( + nameof(ResizeBehavior), + typeof(GridResizeBehavior), + typeof(GridSplitter), + new PropertyMetadata(GridResizeBehavior.BasedOnAlignment)); + + /// + /// Gets or sets which Columns or Rows the Splitter resizes. + /// + public GridResizeBehavior ResizeBehavior + { + get { return (GridResizeBehavior)GetValue(ResizeBehaviorProperty); } + set { SetValue(ResizeBehaviorProperty, value); } + } + } + + /// + /// Enum to indicate what Columns or Rows the GridSplitter resizes + /// + public enum GridResizeBehavior + { + /// + /// Determine which columns or rows to resize based on its Alignment. + /// + BasedOnAlignment, + + /// + /// Resize the current and next Columns or Rows. + /// + CurrentAndNext, + + /// + /// Resize the previous and current Columns or Rows. + /// + PreviousAndCurrent, + + /// + /// Resize the previous and next Columns or Rows. + /// + PreviousAndNext + } +} \ No newline at end of file From 9f2c1624856977b644b8adc60f6be3abea2ea95b Mon Sep 17 00:00:00 2001 From: Darren Batchelor Date: Tue, 4 Jan 2022 16:53:34 -0800 Subject: [PATCH 04/22] split common code out to new base class --- .../ContentSizer/ContentSizer.Events.cs | 48 ---------- .../ContentSizer/ContentSizer.Properties.cs | 3 +- .../GridSplitter/GridSplitter.Options.cs | 44 +++++---- .../GridSplitter/GridSplitter.cs | 2 +- .../GridSplitter/SplitBase.cs | 89 ++++++++++++------- 5 files changed, 78 insertions(+), 108 deletions(-) diff --git a/Microsoft.Toolkit.Uwp.UI.Controls.Layout/ContentSizer/ContentSizer.Events.cs b/Microsoft.Toolkit.Uwp.UI.Controls.Layout/ContentSizer/ContentSizer.Events.cs index 3ce502e5d71..9fca26c7cf1 100644 --- a/Microsoft.Toolkit.Uwp.UI.Controls.Layout/ContentSizer/ContentSizer.Events.cs +++ b/Microsoft.Toolkit.Uwp.UI.Controls.Layout/ContentSizer/ContentSizer.Events.cs @@ -117,53 +117,5 @@ private bool HorizontalMove(double horizontalChange) return false; } - - private bool IsValidHeight(FrameworkElement target, double verticalChange) - { - var newHeight = target.ActualHeight + verticalChange; - - var minHeight = target.MinHeight; - if (newHeight < 0 || (!double.IsNaN(minHeight) && newHeight < minHeight)) - { - return false; - } - - var maxHeight = target.MaxHeight; - if (!double.IsNaN(maxHeight) && newHeight > maxHeight) - { - return false; - } - - if (newHeight <= ActualHeight) - { - return false; - } - - return true; - } - - private bool IsValidWidth(FrameworkElement target, double horizontalChange) - { - var newWidth = target.ActualWidth + horizontalChange; - - var minWidth = target.MinWidth; - if (newWidth < 0 || (!double.IsNaN(minWidth) && newWidth < minWidth)) - { - return false; - } - - var maxWidth = target.MaxWidth; - if (!double.IsNaN(maxWidth) && newWidth > maxWidth) - { - return false; - } - - if (newWidth <= ActualWidth) - { - return false; - } - - return true; - } } } diff --git a/Microsoft.Toolkit.Uwp.UI.Controls.Layout/ContentSizer/ContentSizer.Properties.cs b/Microsoft.Toolkit.Uwp.UI.Controls.Layout/ContentSizer/ContentSizer.Properties.cs index 7e400935841..6b88141953f 100644 --- a/Microsoft.Toolkit.Uwp.UI.Controls.Layout/ContentSizer/ContentSizer.Properties.cs +++ b/Microsoft.Toolkit.Uwp.UI.Controls.Layout/ContentSizer/ContentSizer.Properties.cs @@ -19,7 +19,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Controls public partial class ContentSizer { /// - /// Gets or sets the content template for the . By default is a TextBlock. + /// Gets or sets the content template for the . By default is a TextBlock. /// public DataTemplate ContentTemplate { @@ -47,6 +47,5 @@ public Brush GripperForeground /// public static readonly DependencyProperty GripperForegroundProperty = DependencyProperty.Register(nameof(GripperForeground), typeof(Brush), typeof(ContentSizer), new PropertyMetadata(default(Brush))); - } } diff --git a/Microsoft.Toolkit.Uwp.UI.Controls.Layout/GridSplitter/GridSplitter.Options.cs b/Microsoft.Toolkit.Uwp.UI.Controls.Layout/GridSplitter/GridSplitter.Options.cs index 177536f16a0..86418754d01 100644 --- a/Microsoft.Toolkit.Uwp.UI.Controls.Layout/GridSplitter/GridSplitter.Options.cs +++ b/Microsoft.Toolkit.Uwp.UI.Controls.Layout/GridSplitter/GridSplitter.Options.cs @@ -27,7 +27,7 @@ public static readonly DependencyProperty ElementProperty /// /// Identifies the dependency property. /// - public static readonly DependencyProperty ResizeDirectionProperty + public static new readonly DependencyProperty ResizeDirectionProperty = DependencyProperty.Register( nameof(ResizeDirection), typeof(GridResizeDirection), @@ -35,14 +35,14 @@ public static readonly DependencyProperty ResizeDirectionProperty new PropertyMetadata(GridResizeDirection.Auto)); /// - ///// Identifies the dependency property. - ///// - //public static readonly DependencyProperty ResizeBehaviorProperty - // = DependencyProperty.Register( - // nameof(ResizeBehavior), - // typeof(GridResizeBehavior), - // typeof(GridSplitter), - // new PropertyMetadata(GridResizeBehavior.BasedOnAlignment)); + /// Identifies the dependency property. + /// + public static readonly DependencyProperty ResizeBehaviorProperty + = DependencyProperty.Register( + nameof(ResizeBehavior), + typeof(GridResizeBehavior), + typeof(GridSplitter), + new PropertyMetadata(GridResizeBehavior.BasedOnAlignment)); /// /// Identifies the dependency property. @@ -67,7 +67,7 @@ public static readonly DependencyProperty ParentLevelProperty /// /// Identifies the dependency property. /// - public static readonly DependencyProperty GripperCursorProperty = + public static new readonly DependencyProperty GripperCursorProperty = DependencyProperty.RegisterAttached( nameof(GripperCursor), typeof(CoreCursorType?), @@ -106,22 +106,20 @@ public UIElement Element /// /// Gets or sets whether the Splitter resizes the Columns, Rows, or Both. /// - public GridResizeDirection ResizeDirection + public new GridResizeDirection ResizeDirection { get { return (GridResizeDirection)GetValue(ResizeDirectionProperty); } - set { SetValue(ResizeDirectionProperty, value); } } - ///// - ///// Gets or sets which Columns or Rows the Splitter resizes. - ///// - //public GridResizeBehavior ResizeBehavior - //{ - // get { return (GridResizeBehavior)GetValue(ResizeBehaviorProperty); } - - // set { SetValue(ResizeBehaviorProperty, value); } - //} + /// + /// Gets or sets which Columns or Rows the Splitter resizes. + /// + public GridResizeBehavior ResizeBehavior + { + get { return (GridResizeBehavior)GetValue(ResizeBehaviorProperty); } + set { SetValue(ResizeBehaviorProperty, value); } + } /// /// Gets or sets the foreground color of grid splitter grip @@ -129,7 +127,6 @@ public GridResizeDirection ResizeDirection public Brush GripperForeground { get { return (Brush)GetValue(GripperForegroundProperty); } - set { SetValue(GripperForegroundProperty, value); } } @@ -139,14 +136,13 @@ public Brush GripperForeground public int ParentLevel { get { return (int)GetValue(ParentLevelProperty); } - set { SetValue(ParentLevelProperty, value); } } /// /// Gets or sets the gripper Cursor type /// - public GripperCursorType GripperCursor + public new GripperCursorType GripperCursor { get { return (GripperCursorType)GetValue(GripperCursorProperty); } set { SetValue(GripperCursorProperty, value); } diff --git a/Microsoft.Toolkit.Uwp.UI.Controls.Layout/GridSplitter/GridSplitter.cs b/Microsoft.Toolkit.Uwp.UI.Controls.Layout/GridSplitter/GridSplitter.cs index b53cda9c7d1..5cc556ee3b4 100644 --- a/Microsoft.Toolkit.Uwp.UI.Controls.Layout/GridSplitter/GridSplitter.cs +++ b/Microsoft.Toolkit.Uwp.UI.Controls.Layout/GridSplitter/GridSplitter.cs @@ -13,7 +13,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Controls /// /// Represents the control that redistributes space between columns or rows of a Grid control. /// - public partial class GridSplitter : Control + public partial class GridSplitter : SplitBase { internal const int GripperCustomCursorDefaultResource = -1; internal static readonly CoreCursor ColumnsSplitterCursor = new CoreCursor(CoreCursorType.SizeWestEast, 1); diff --git a/Microsoft.Toolkit.Uwp.UI.Controls.Layout/GridSplitter/SplitBase.cs b/Microsoft.Toolkit.Uwp.UI.Controls.Layout/GridSplitter/SplitBase.cs index 4090d829f33..33c702adb50 100644 --- a/Microsoft.Toolkit.Uwp.UI.Controls.Layout/GridSplitter/SplitBase.cs +++ b/Microsoft.Toolkit.Uwp.UI.Controls.Layout/GridSplitter/SplitBase.cs @@ -1,3 +1,7 @@ +// 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 System.Collections.Generic; using System.Linq; @@ -9,6 +13,9 @@ namespace Microsoft.Toolkit.Uwp.UI.Controls { + /// + /// Base class for GridSplitter and ContentSizer + /// public partial class SplitBase : Control { /// @@ -89,48 +96,64 @@ private static void OnTargetControlChanged(DependencyObject d, DependencyPropert } } - /// Identifies the dependency property. - /// - public static readonly DependencyProperty ResizeBehaviorProperty - = DependencyProperty.Register( - nameof(ResizeBehavior), - typeof(GridResizeBehavior), - typeof(GridSplitter), - new PropertyMetadata(GridResizeBehavior.BasedOnAlignment)); - /// - /// Gets or sets which Columns or Rows the Splitter resizes. + /// Check for new requested vertical size is valid or not /// - public GridResizeBehavior ResizeBehavior + /// Target control being resized + /// The requested vertical change + /// Bool result if requested vertical change is valid or not + protected bool IsValidHeight(FrameworkElement target, double verticalChange) { - get { return (GridResizeBehavior)GetValue(ResizeBehaviorProperty); } - set { SetValue(ResizeBehaviorProperty, value); } + var newHeight = target.ActualHeight + verticalChange; + + var minHeight = target.MinHeight; + if (newHeight < 0 || (!double.IsNaN(minHeight) && newHeight < minHeight)) + { + return false; + } + + var maxHeight = target.MaxHeight; + if (!double.IsNaN(maxHeight) && newHeight > maxHeight) + { + return false; + } + + if (newHeight <= ActualHeight) + { + return false; + } + + return true; } - } - /// - /// Enum to indicate what Columns or Rows the GridSplitter resizes - /// - public enum GridResizeBehavior - { /// - /// Determine which columns or rows to resize based on its Alignment. + /// Check for new requested horizontal size is valid or not /// - BasedOnAlignment, + /// Target control being resized + /// The requested horizontal change + /// Bool result if requested horizontal change is valid or not + protected bool IsValidWidth(FrameworkElement target, double horizontalChange) + { + var newWidth = target.ActualWidth + horizontalChange; - /// - /// Resize the current and next Columns or Rows. - /// - CurrentAndNext, + var minWidth = target.MinWidth; + if (newWidth < 0 || (!double.IsNaN(minWidth) && newWidth < minWidth)) + { + return false; + } - /// - /// Resize the previous and current Columns or Rows. - /// - PreviousAndCurrent, + var maxWidth = target.MaxWidth; + if (!double.IsNaN(maxWidth) && newWidth > maxWidth) + { + return false; + } - /// - /// Resize the previous and next Columns or Rows. - /// - PreviousAndNext + if (newWidth <= ActualWidth) + { + return false; + } + + return true; + } } } \ No newline at end of file From 22b9c75d618ec314b7af5e8761d3ee44ace9a54f Mon Sep 17 00:00:00 2001 From: Darren Batchelor Date: Wed, 5 Jan 2022 14:00:08 -0800 Subject: [PATCH 05/22] Implement appropriate cursor shape --- .../ContentSizer/ContentSizer.Events.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Microsoft.Toolkit.Uwp.UI.Controls.Layout/ContentSizer/ContentSizer.Events.cs b/Microsoft.Toolkit.Uwp.UI.Controls.Layout/ContentSizer/ContentSizer.Events.cs index 9fca26c7cf1..48c2a7db31a 100644 --- a/Microsoft.Toolkit.Uwp.UI.Controls.Layout/ContentSizer/ContentSizer.Events.cs +++ b/Microsoft.Toolkit.Uwp.UI.Controls.Layout/ContentSizer/ContentSizer.Events.cs @@ -97,6 +97,8 @@ private bool VerticalMove(double verticalChange) // Do we need our ContentResizeDirection to be 4 way? Maybe 'Auto' would check the horizontal/vertical alignment of the target??? TargetControl.Height += verticalChange; + GripperCursor = Windows.UI.Core.CoreCursorType.SizeNorthSouth; + return false; } @@ -115,6 +117,8 @@ private bool HorizontalMove(double horizontalChange) // TODO: This only works if splitter is on left and making things grow right... TargetControl.Width += horizontalChange; + GripperCursor = Windows.UI.Core.CoreCursorType.SizeWestEast; + return false; } } From 3f3f447b7feec8f788f3210afba9bfd14397a49c Mon Sep 17 00:00:00 2001 From: Darren Batchelor Date: Wed, 5 Jan 2022 16:56:36 -0800 Subject: [PATCH 06/22] stage automation peer class --- .../ContentSizerAutomationPeer.cs | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 Microsoft.Toolkit.Uwp.UI.Controls.Layout/ContentSizer/ContentSizerAutomationPeer.cs diff --git a/Microsoft.Toolkit.Uwp.UI.Controls.Layout/ContentSizer/ContentSizerAutomationPeer.cs b/Microsoft.Toolkit.Uwp.UI.Controls.Layout/ContentSizer/ContentSizerAutomationPeer.cs new file mode 100644 index 00000000000..86045fc8567 --- /dev/null +++ b/Microsoft.Toolkit.Uwp.UI.Controls.Layout/ContentSizer/ContentSizerAutomationPeer.cs @@ -0,0 +1,22 @@ +using Windows.UI.Xaml; +using Windows.UI.Xaml.Automation.Peers; +using Microsoft.Toolkit.Uwp.UI.Controls; + +namespace Microsoft.Toolkit.Uwp.UI.Controls.ContentSizer +{ + public class ContentSizerAutomationPeer : FrameworkElementAutomationPeer + { + public ContentSizerAutomationPeer(SplitBase owner) : base(owner) + { + + } + + private ContentSizer OwningContentSizer + { + get + { + return Owner as ContentSizer; + } + } + } +} From 71de3f9ddfaf0c818610ebee84ca5d343796ad1b Mon Sep 17 00:00:00 2001 From: Darren Batchelor Date: Thu, 6 Jan 2022 12:50:42 -0800 Subject: [PATCH 07/22] add unit test for AutomationPeer --- .../ContentSizer/ContentSizer.cs | 10 ++++ .../ContentSizerAutomationPeer.cs | 60 +++++++++++++++++-- .../UI/Controls/Test_ContentSizer.cs | 35 +++++++++++ UnitTests/UnitTests.UWP/UnitTests.UWP.csproj | 1 + 4 files changed, 102 insertions(+), 4 deletions(-) create mode 100644 UnitTests/UnitTests.UWP/UI/Controls/Test_ContentSizer.cs diff --git a/Microsoft.Toolkit.Uwp.UI.Controls.Layout/ContentSizer/ContentSizer.cs b/Microsoft.Toolkit.Uwp.UI.Controls.Layout/ContentSizer/ContentSizer.cs index 6d040c63ee6..8eb1a8f5c86 100644 --- a/Microsoft.Toolkit.Uwp.UI.Controls.Layout/ContentSizer/ContentSizer.cs +++ b/Microsoft.Toolkit.Uwp.UI.Controls.Layout/ContentSizer/ContentSizer.cs @@ -2,6 +2,7 @@ // 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.Automation.Peers; using Windows.UI.Xaml.Controls; using Windows.UI.Xaml.Input; using Windows.UI.Xaml.Markup; @@ -46,5 +47,14 @@ protected override void OnApplyTemplate() // Register Events Loaded += ContentSizer_Loaded; } + + /// + /// Creates AutomationPeer () + /// + /// An automation peer for this . + protected override AutomationPeer OnCreateAutomationPeer() + { + return new ContentSizerAutomationPeer(this); + } } } diff --git a/Microsoft.Toolkit.Uwp.UI.Controls.Layout/ContentSizer/ContentSizerAutomationPeer.cs b/Microsoft.Toolkit.Uwp.UI.Controls.Layout/ContentSizer/ContentSizerAutomationPeer.cs index 86045fc8567..40f3bd945d6 100644 --- a/Microsoft.Toolkit.Uwp.UI.Controls.Layout/ContentSizer/ContentSizerAutomationPeer.cs +++ b/Microsoft.Toolkit.Uwp.UI.Controls.Layout/ContentSizer/ContentSizerAutomationPeer.cs @@ -1,12 +1,22 @@ -using Windows.UI.Xaml; -using Windows.UI.Xaml.Automation.Peers; +// 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 Microsoft.Toolkit.Uwp.UI.Controls; +using Windows.UI.Xaml.Automation; +using Windows.UI.Xaml.Automation.Peers; -namespace Microsoft.Toolkit.Uwp.UI.Controls.ContentSizer +namespace Microsoft.Toolkit.Uwp.UI.Automation.Peers { public class ContentSizerAutomationPeer : FrameworkElementAutomationPeer { - public ContentSizerAutomationPeer(SplitBase owner) : base(owner) + /// + /// Initializes a new instance of the class. + /// + /// + /// The that is associated with this . + /// + public ContentSizerAutomationPeer(ContentSizer owner) : base(owner) { } @@ -18,5 +28,47 @@ private ContentSizer OwningContentSizer return Owner as ContentSizer; } } + + /// + /// Called by GetClassName that gets a human readable name that, in addition to AutomationControlType, + /// differentiates the control represented by this AutomationPeer. + /// + /// The string that contains the name. + protected override string GetClassNameCore() + { + return Owner.GetType().Name; + } + + /// + /// Called by GetName. + /// + /// + /// Returns the first of these that is not null or empty: + /// - Value returned by the base implementation + /// - Name of the owning ContentSizer + /// - ContentSizer class name + /// + protected override string GetNameCore() + { + string name = AutomationProperties.GetName(this.OwningContentSizer); + if (!string.IsNullOrEmpty(name)) + { + return name; + } + + name = this.OwningContentSizer.Name; + if (!string.IsNullOrEmpty(name)) + { + return name; + } + + name = base.GetNameCore(); + if (!string.IsNullOrEmpty(name)) + { + return name; + } + + return string.Empty; + } } } diff --git a/UnitTests/UnitTests.UWP/UI/Controls/Test_ContentSizer.cs b/UnitTests/UnitTests.UWP/UI/Controls/Test_ContentSizer.cs new file mode 100644 index 00000000000..f64ef383104 --- /dev/null +++ b/UnitTests/UnitTests.UWP/UI/Controls/Test_ContentSizer.cs @@ -0,0 +1,35 @@ +// 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 Microsoft.Toolkit.Uwp.UI.Controls; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Microsoft.VisualStudio.TestTools.UnitTesting.AppContainer; +using Windows.UI.Xaml.Automation; +using Windows.UI.Xaml.Automation.Peers; + +namespace UnitTests.UWP.UI.Controls +{ + [TestClass] + [TestCategory("Test_ContentSizer")] + public class Test_ContentSizer + { + [UITestMethod] + public void ShouldConfigureContentSizerAutomationPeer() + { + const string automationName = "MyContentSizer"; + const string name = "ContentSizer"; + + var contentSizer = new ContentSizer(); + var contentSizerAutomationPeer = FrameworkElementAutomationPeer.CreatePeerForElement(contentSizer) as ContentSizerAutomationPeer; + + Assert.IsNotNull(contentSizerAutomationPeer, "Verify that the AutomationPeer is ContentSizerAutomationPeer."); + + contentSizer.Name = name; + Assert.IsTrue(contentSizerAutomationPeer.GetName().Contains(name), "Verify that the UIA name contains the given Name of the ContentSizer."); + + contentSizer.SetValue(AutomationProperties.NameProperty, automationName); + Assert.IsTrue(contentSizerAutomationPeer.GetName().Contains(automationName), "Verify that the UIA name contains the given AutomationProperties.Name of the ContentSizer."); + } + } +} diff --git a/UnitTests/UnitTests.UWP/UnitTests.UWP.csproj b/UnitTests/UnitTests.UWP/UnitTests.UWP.csproj index d50b438032e..771f2a76567 100644 --- a/UnitTests/UnitTests.UWP/UnitTests.UWP.csproj +++ b/UnitTests/UnitTests.UWP/UnitTests.UWP.csproj @@ -243,6 +243,7 @@ + From 2e0dceb31ceded1a07b5db3250643a6a8932f329 Mon Sep 17 00:00:00 2001 From: Darren Batchelor Date: Thu, 6 Jan 2022 14:13:08 -0800 Subject: [PATCH 08/22] changes for test --- .../ContentSizer/ContentSizer.cs | 2 ++ .../ContentSizer/ContentSizerAutomationPeer.cs | 7 +++++-- UnitTests/UnitTests.UWP/UI/Controls/Test_ContentSizer.cs | 1 + 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/Microsoft.Toolkit.Uwp.UI.Controls.Layout/ContentSizer/ContentSizer.cs b/Microsoft.Toolkit.Uwp.UI.Controls.Layout/ContentSizer/ContentSizer.cs index 8eb1a8f5c86..57388197527 100644 --- a/Microsoft.Toolkit.Uwp.UI.Controls.Layout/ContentSizer/ContentSizer.cs +++ b/Microsoft.Toolkit.Uwp.UI.Controls.Layout/ContentSizer/ContentSizer.cs @@ -2,6 +2,8 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using Microsoft.Toolkit.Uwp.UI.Automation.Peers; +using Windows.UI.Xaml; using Windows.UI.Xaml.Automation.Peers; using Windows.UI.Xaml.Controls; using Windows.UI.Xaml.Input; diff --git a/Microsoft.Toolkit.Uwp.UI.Controls.Layout/ContentSizer/ContentSizerAutomationPeer.cs b/Microsoft.Toolkit.Uwp.UI.Controls.Layout/ContentSizer/ContentSizerAutomationPeer.cs index 40f3bd945d6..9a9e71f3e19 100644 --- a/Microsoft.Toolkit.Uwp.UI.Controls.Layout/ContentSizer/ContentSizerAutomationPeer.cs +++ b/Microsoft.Toolkit.Uwp.UI.Controls.Layout/ContentSizer/ContentSizerAutomationPeer.cs @@ -8,6 +8,9 @@ namespace Microsoft.Toolkit.Uwp.UI.Automation.Peers { + /// + /// Defines a framework element automation peer for the control. + /// public class ContentSizerAutomationPeer : FrameworkElementAutomationPeer { /// @@ -16,9 +19,9 @@ public class ContentSizerAutomationPeer : FrameworkElementAutomationPeer /// /// The that is associated with this . /// - public ContentSizerAutomationPeer(ContentSizer owner) : base(owner) + public ContentSizerAutomationPeer(ContentSizer owner) + : base(owner) { - } private ContentSizer OwningContentSizer diff --git a/UnitTests/UnitTests.UWP/UI/Controls/Test_ContentSizer.cs b/UnitTests/UnitTests.UWP/UI/Controls/Test_ContentSizer.cs index f64ef383104..6cef47822f8 100644 --- a/UnitTests/UnitTests.UWP/UI/Controls/Test_ContentSizer.cs +++ b/UnitTests/UnitTests.UWP/UI/Controls/Test_ContentSizer.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using Microsoft.Toolkit.Uwp.UI.Automation.Peers; using Microsoft.Toolkit.Uwp.UI.Controls; using Microsoft.VisualStudio.TestTools.UnitTesting; using Microsoft.VisualStudio.TestTools.UnitTesting.AppContainer; From a4c1ff3dacaa007d763c68df1eba01e022377ea6 Mon Sep 17 00:00:00 2001 From: Darren Batchelor Date: Tue, 11 Jan 2022 16:30:30 -0800 Subject: [PATCH 09/22] InvertDragDirection --- .../ContentSizer/ContentSizer.Events.cs | 4 ++++ .../GridSplitter/SplitBase.cs | 15 +++++++++++++++ 2 files changed, 19 insertions(+) diff --git a/Microsoft.Toolkit.Uwp.UI.Controls.Layout/ContentSizer/ContentSizer.Events.cs b/Microsoft.Toolkit.Uwp.UI.Controls.Layout/ContentSizer/ContentSizer.Events.cs index 48c2a7db31a..8bb652e809d 100644 --- a/Microsoft.Toolkit.Uwp.UI.Controls.Layout/ContentSizer/ContentSizer.Events.cs +++ b/Microsoft.Toolkit.Uwp.UI.Controls.Layout/ContentSizer/ContentSizer.Events.cs @@ -88,6 +88,8 @@ private bool VerticalMove(double verticalChange) return true; } + verticalChange = InvertDragDirection ? -verticalChange : verticalChange; + if (!IsValidHeight(TargetControl, verticalChange)) { return true; @@ -109,6 +111,8 @@ private bool HorizontalMove(double horizontalChange) return true; } + horizontalChange = InvertDragDirection ? -horizontalChange : horizontalChange; + if (!IsValidWidth(TargetControl, horizontalChange)) { return true; diff --git a/Microsoft.Toolkit.Uwp.UI.Controls.Layout/GridSplitter/SplitBase.cs b/Microsoft.Toolkit.Uwp.UI.Controls.Layout/GridSplitter/SplitBase.cs index 33c702adb50..62aed6fa154 100644 --- a/Microsoft.Toolkit.Uwp.UI.Controls.Layout/GridSplitter/SplitBase.cs +++ b/Microsoft.Toolkit.Uwp.UI.Controls.Layout/GridSplitter/SplitBase.cs @@ -96,6 +96,21 @@ private static void OnTargetControlChanged(DependencyObject d, DependencyPropert } } + /// + /// Gets or sets a value indicating whether the control is resizing in the opposite direction. + /// + public bool InvertDragDirection + { + get { return (bool)GetValue(InvertDragDirectionProperty); } + set { SetValue(InvertDragDirectionProperty, value); } + } + + /// + /// Identifies the dependency property. + /// + public static readonly DependencyProperty InvertDragDirectionProperty = + DependencyProperty.Register(nameof(InvertDragDirection), typeof(bool), typeof(SplitBase), new PropertyMetadata(false)); + /// /// Check for new requested vertical size is valid or not /// From 41b7ec3db2cbad5dfaee9322d43bd2ed34c2b239 Mon Sep 17 00:00:00 2001 From: Darren Batchelor Date: Thu, 13 Jan 2022 12:54:46 -0800 Subject: [PATCH 10/22] Remove GripperHoverWrapper --- .../ContentSizer/ContentSizer.Properties.cs | 51 ------ .../ContentSizer/ContentSizer.cs | 15 ++ .../GridSplitter/GridSplitter.Events.cs | 15 -- .../GridSplitter/GridSplitter.Options.cs | 111 +----------- .../GridSplitter/GridSplitter.cs | 18 +- .../GridSplitter/GridSplitter.xaml | 3 +- .../GridSplitter/GripperHoverWrapper.cs | 169 ------------------ .../GridSplitter/SplitBase.cs | 21 ++- 8 files changed, 48 insertions(+), 355 deletions(-) delete mode 100644 Microsoft.Toolkit.Uwp.UI.Controls.Layout/ContentSizer/ContentSizer.Properties.cs delete mode 100644 Microsoft.Toolkit.Uwp.UI.Controls.Layout/GridSplitter/GripperHoverWrapper.cs diff --git a/Microsoft.Toolkit.Uwp.UI.Controls.Layout/ContentSizer/ContentSizer.Properties.cs b/Microsoft.Toolkit.Uwp.UI.Controls.Layout/ContentSizer/ContentSizer.Properties.cs deleted file mode 100644 index 6b88141953f..00000000000 --- a/Microsoft.Toolkit.Uwp.UI.Controls.Layout/ContentSizer/ContentSizer.Properties.cs +++ /dev/null @@ -1,51 +0,0 @@ -// 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 System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using Windows.UI.Core; -using Windows.UI.Xaml; -using Windows.UI.Xaml.Media; - -namespace Microsoft.Toolkit.Uwp.UI.Controls -{ - /// - /// Properties of the control. - /// - public partial class ContentSizer - { - /// - /// Gets or sets the content template for the . By default is a TextBlock. - /// - public DataTemplate ContentTemplate - { - get { return (DataTemplate)GetValue(ContentTemplateProperty); } - set { SetValue(ContentTemplateProperty, value); } - } - - /// - /// Identifies the dependency property. - /// - public static readonly DependencyProperty ContentTemplateProperty = - DependencyProperty.Register(nameof(ContentTemplate), typeof(DataTemplate), typeof(ContentSizer), new PropertyMetadata(null)); - - /// - /// Gets or sets the foreground color of sizer grip. - /// - public Brush GripperForeground - { - get { return (Brush)GetValue(GripperForegroundProperty); } - set { SetValue(GripperForegroundProperty, value); } - } - - /// - /// Identifies the dependency property. - /// - public static readonly DependencyProperty GripperForegroundProperty = - DependencyProperty.Register(nameof(GripperForeground), typeof(Brush), typeof(ContentSizer), new PropertyMetadata(default(Brush))); - } -} diff --git a/Microsoft.Toolkit.Uwp.UI.Controls.Layout/ContentSizer/ContentSizer.cs b/Microsoft.Toolkit.Uwp.UI.Controls.Layout/ContentSizer/ContentSizer.cs index 57388197527..09377d6f148 100644 --- a/Microsoft.Toolkit.Uwp.UI.Controls.Layout/ContentSizer/ContentSizer.cs +++ b/Microsoft.Toolkit.Uwp.UI.Controls.Layout/ContentSizer/ContentSizer.cs @@ -23,6 +23,21 @@ public partial class ContentSizer : SplitBase private const double GripperKeyboardChange = 8.0d; + /// + /// Gets or sets the content template for the . By default is a TextBlock. + /// + public DataTemplate ContentTemplate + { + get { return (DataTemplate)GetValue(ContentTemplateProperty); } + set { SetValue(ContentTemplateProperty, value); } + } + + /// + /// Identifies the dependency property. + /// + public static readonly DependencyProperty ContentTemplateProperty = + DependencyProperty.Register(nameof(ContentTemplate), typeof(DataTemplate), typeof(ContentSizer), new PropertyMetadata(null)); + /// /// Initializes a new instance of the class. /// diff --git a/Microsoft.Toolkit.Uwp.UI.Controls.Layout/GridSplitter/GridSplitter.Events.cs b/Microsoft.Toolkit.Uwp.UI.Controls.Layout/GridSplitter/GridSplitter.Events.cs index a310d1b7d03..17a25abb3f5 100644 --- a/Microsoft.Toolkit.Uwp.UI.Controls.Layout/GridSplitter/GridSplitter.Events.cs +++ b/Microsoft.Toolkit.Uwp.UI.Controls.Layout/GridSplitter/GridSplitter.Events.cs @@ -32,21 +32,6 @@ private void GridSplitter_Loaded(object sender, RoutedEventArgs e) CreateGripperDisplay(); Element = _gripperDisplay; } - - if (_hoverWrapper == null) - { - var hoverWrapper = new GripperHoverWrapper( - CursorBehavior == SplitterCursorBehavior.ChangeOnSplitterHover - ? this - : Element, - _resizeDirection, - GripperCursor, - GripperCustomCursorResource); - ManipulationStarted += hoverWrapper.SplitterManipulationStarted; - ManipulationCompleted += hoverWrapper.SplitterManipulationCompleted; - - _hoverWrapper = hoverWrapper; - } } private void CreateGripperDisplay() diff --git a/Microsoft.Toolkit.Uwp.UI.Controls.Layout/GridSplitter/GridSplitter.Options.cs b/Microsoft.Toolkit.Uwp.UI.Controls.Layout/GridSplitter/GridSplitter.Options.cs index 86418754d01..a1cd0eaf049 100644 --- a/Microsoft.Toolkit.Uwp.UI.Controls.Layout/GridSplitter/GridSplitter.Options.cs +++ b/Microsoft.Toolkit.Uwp.UI.Controls.Layout/GridSplitter/GridSplitter.Options.cs @@ -2,10 +2,7 @@ // 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.Core; using Windows.UI.Xaml; -using Windows.UI.Xaml.Controls; -using Windows.UI.Xaml.Media; namespace Microsoft.Toolkit.Uwp.UI.Controls { @@ -22,7 +19,7 @@ public static readonly DependencyProperty ElementProperty nameof(Element), typeof(UIElement), typeof(GridSplitter), - new PropertyMetadata(default(UIElement), OnElementPropertyChanged)); + new PropertyMetadata(default(UIElement))); /// /// Identifies the dependency property. @@ -44,16 +41,6 @@ public static readonly DependencyProperty ResizeBehaviorProperty typeof(GridSplitter), new PropertyMetadata(GridResizeBehavior.BasedOnAlignment)); - /// - /// Identifies the dependency property. - /// - public static readonly DependencyProperty GripperForegroundProperty - = DependencyProperty.Register( - nameof(GripperForeground), - typeof(Brush), - typeof(GridSplitter), - new PropertyMetadata(default(Brush), OnGripperForegroundPropertyChanged)); - /// /// Identifies the dependency property. /// @@ -64,26 +51,6 @@ public static readonly DependencyProperty ParentLevelProperty typeof(GridSplitter), new PropertyMetadata(default(int))); - /// - /// Identifies the dependency property. - /// - public static new readonly DependencyProperty GripperCursorProperty = - DependencyProperty.RegisterAttached( - nameof(GripperCursor), - typeof(CoreCursorType?), - typeof(GridSplitter), - new PropertyMetadata(GripperCursorType.Default, OnGripperCursorPropertyChanged)); - - /// - /// Identifies the dependency property. - /// - public static readonly DependencyProperty GripperCustomCursorResourceProperty = - DependencyProperty.RegisterAttached( - nameof(GripperCustomCursorResource), - typeof(uint), - typeof(GridSplitter), - new PropertyMetadata(GripperCustomCursorDefaultResource, GripperCustomCursorResourcePropertyChanged)); - /// /// Identifies the dependency property. /// @@ -92,7 +59,7 @@ public static readonly DependencyProperty ParentLevelProperty nameof(CursorBehavior), typeof(SplitterCursorBehavior), typeof(GridSplitter), - new PropertyMetadata(SplitterCursorBehavior.ChangeOnSplitterHover, CursorBehaviorPropertyChanged)); + new PropertyMetadata(SplitterCursorBehavior.ChangeOnSplitterHover)); /// /// Gets or sets the visual content of this Grid Splitter @@ -121,15 +88,6 @@ public GridResizeBehavior ResizeBehavior set { SetValue(ResizeBehaviorProperty, value); } } - /// - /// Gets or sets the foreground color of grid splitter grip - /// - public Brush GripperForeground - { - get { return (Brush)GetValue(GripperForegroundProperty); } - set { SetValue(GripperForegroundProperty, value); } - } - /// /// Gets or sets the level of the parent grid to resize /// @@ -148,15 +106,6 @@ public int ParentLevel set { SetValue(GripperCursorProperty, value); } } - /// - /// Gets or sets the gripper Custom Cursor resource number - /// - public int GripperCustomCursorResource - { - get { return (int)GetValue(GripperCustomCursorResourceProperty); } - set { SetValue(GripperCustomCursorResourceProperty, value); } - } - /// /// Gets or sets splitter cursor on hover behavior /// @@ -165,61 +114,5 @@ public SplitterCursorBehavior CursorBehavior get { return (SplitterCursorBehavior)GetValue(CursorBehaviorProperty); } set { SetValue(CursorBehaviorProperty, value); } } - - private static void OnGripperForegroundPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - var gridSplitter = (GridSplitter)d; - - if (gridSplitter._gripperDisplay == null) - { - return; - } - - gridSplitter._gripperDisplay.Foreground = gridSplitter.GripperForeground; - } - - private static void OnGripperCursorPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - var gridSplitter = (GridSplitter)d; - - if (gridSplitter._hoverWrapper == null) - { - return; - } - - gridSplitter._hoverWrapper.GripperCursor = gridSplitter.GripperCursor; - } - - private static void GripperCustomCursorResourcePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - var gridSplitter = (GridSplitter)d; - - if (gridSplitter._hoverWrapper == null) - { - return; - } - - gridSplitter._hoverWrapper.GripperCustomCursorResource = gridSplitter.GripperCustomCursorResource; - } - - private static void CursorBehaviorPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - var gridSplitter = (GridSplitter)d; - - gridSplitter._hoverWrapper?.UpdateHoverElement(gridSplitter.CursorBehavior == - SplitterCursorBehavior.ChangeOnSplitterHover - ? gridSplitter - : gridSplitter.Element); - } - - private static void OnElementPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - var gridSplitter = (GridSplitter)d; - - gridSplitter._hoverWrapper?.UpdateHoverElement(gridSplitter.CursorBehavior == - SplitterCursorBehavior.ChangeOnSplitterHover - ? gridSplitter - : gridSplitter.Element); - } } } \ No newline at end of file diff --git a/Microsoft.Toolkit.Uwp.UI.Controls.Layout/GridSplitter/GridSplitter.cs b/Microsoft.Toolkit.Uwp.UI.Controls.Layout/GridSplitter/GridSplitter.cs index 5cc556ee3b4..57bc456e33d 100644 --- a/Microsoft.Toolkit.Uwp.UI.Controls.Layout/GridSplitter/GridSplitter.cs +++ b/Microsoft.Toolkit.Uwp.UI.Controls.Layout/GridSplitter/GridSplitter.cs @@ -23,7 +23,7 @@ public partial class GridSplitter : SplitBase private GridResizeDirection _resizeDirection; private GridResizeBehavior _resizeBehavior; - private GripperHoverWrapper _hoverWrapper; + private TextBlock _gripperDisplay; private bool _pressed = false; @@ -166,6 +166,18 @@ public GridSplitter() Loaded += GridSplitter_Loaded; string automationName = "WCT_GridSplitter_AutomationName".GetLocalized("Microsoft.Toolkit.Uwp.UI.Controls.Layout/Resources"); AutomationProperties.SetName(this, automationName); + + RegisterPropertyChangedCallback(GripperForegroundProperty, (sender, eventArgs) => + { + var gridSplitter = (GridSplitter)sender; + + if (gridSplitter._gripperDisplay == null) + { + return; + } + + gridSplitter._gripperDisplay.Foreground = gridSplitter.GripperForeground; + }); } /// @@ -182,8 +194,6 @@ protected override void OnApplyTemplate() ManipulationStarted -= GridSplitter_ManipulationStarted; ManipulationCompleted -= GridSplitter_ManipulationCompleted; - _hoverWrapper?.UnhookEvents(); - // Register Events Loaded += GridSplitter_Loaded; PointerEntered += GridSplitter_PointerEntered; @@ -193,8 +203,6 @@ protected override void OnApplyTemplate() ManipulationStarted += GridSplitter_ManipulationStarted; ManipulationCompleted += GridSplitter_ManipulationCompleted; - _hoverWrapper?.UpdateHoverElement(Element); - ManipulationMode = ManipulationModes.TranslateX | ManipulationModes.TranslateY; } diff --git a/Microsoft.Toolkit.Uwp.UI.Controls.Layout/GridSplitter/GridSplitter.xaml b/Microsoft.Toolkit.Uwp.UI.Controls.Layout/GridSplitter/GridSplitter.xaml index 451e054d16f..bd81b67d5f4 100644 --- a/Microsoft.Toolkit.Uwp.UI.Controls.Layout/GridSplitter/GridSplitter.xaml +++ b/Microsoft.Toolkit.Uwp.UI.Controls.Layout/GridSplitter/GridSplitter.xaml @@ -1,6 +1,7 @@ + xmlns:local="using:Microsoft.Toolkit.Uwp.UI.Controls" + xmlns:ui="using:Microsoft.Toolkit.Uwp.UI"> diff --git a/Microsoft.Toolkit.Uwp.UI.Controls.Layout/GridSplitter/GripperHoverWrapper.cs b/Microsoft.Toolkit.Uwp.UI.Controls.Layout/GridSplitter/GripperHoverWrapper.cs deleted file mode 100644 index 6b22b204886..00000000000 --- a/Microsoft.Toolkit.Uwp.UI.Controls.Layout/GridSplitter/GripperHoverWrapper.cs +++ /dev/null @@ -1,169 +0,0 @@ -// 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.Core; -using Windows.UI.Xaml; -using Windows.UI.Xaml.Input; - -namespace Microsoft.Toolkit.Uwp.UI.Controls -{ - internal class GripperHoverWrapper - { - private readonly GridSplitter.GridResizeDirection _gridSplitterDirection; - - private CoreCursor _splitterPreviousPointer; - private CoreCursor _previousCursor; - private GridSplitter.GripperCursorType _gripperCursor; - private int _gripperCustomCursorResource; - private bool _isDragging; - private UIElement _element; - - internal GridSplitter.GripperCursorType GripperCursor - { - get - { - return _gripperCursor; - } - - set - { - _gripperCursor = value; - } - } - - internal int GripperCustomCursorResource - { - get - { - return _gripperCustomCursorResource; - } - - set - { - _gripperCustomCursorResource = value; - } - } - - /// - /// Initializes a new instance of the class that add cursor change on hover functionality for GridSplitter. - /// - /// UI element to apply cursor change on hover - /// GridSplitter resize direction - /// GridSplitter gripper on hover cursor type - /// GridSplitter gripper custom cursor resource number - internal GripperHoverWrapper(UIElement element, GridSplitter.GridResizeDirection gridSplitterDirection, GridSplitter.GripperCursorType gripperCursor, int gripperCustomCursorResource) - { - _gridSplitterDirection = gridSplitterDirection; - _gripperCursor = gripperCursor; - _gripperCustomCursorResource = gripperCustomCursorResource; - _element = element; - UnhookEvents(); - _element.PointerEntered += Element_PointerEntered; - _element.PointerExited += Element_PointerExited; - } - - internal void UpdateHoverElement(UIElement element) - { - UnhookEvents(); - _element = element; - _element.PointerEntered += Element_PointerEntered; - _element.PointerExited += Element_PointerExited; - } - - private void Element_PointerExited(object sender, PointerRoutedEventArgs e) - { - if (_isDragging) - { - // if dragging don't update the cursor just update the splitter cursor with the last window cursor, - // because the splitter is still using the arrow cursor and will revert to original case when drag completes - _splitterPreviousPointer = _previousCursor; - } - else - { - Window.Current.CoreWindow.PointerCursor = _previousCursor; - } - } - - private void Element_PointerEntered(object sender, PointerRoutedEventArgs e) - { - // if not dragging - if (!_isDragging) - { - _previousCursor = _splitterPreviousPointer = Window.Current.CoreWindow.PointerCursor; - UpdateDisplayCursor(); - } - - // if dragging - else - { - _previousCursor = _splitterPreviousPointer; - } - } - - private void UpdateDisplayCursor() - { - if (_gripperCursor == GridSplitter.GripperCursorType.Default) - { - if (_gridSplitterDirection == GridSplitter.GridResizeDirection.Columns) - { - Window.Current.CoreWindow.PointerCursor = GridSplitter.ColumnsSplitterCursor; - } - else if (_gridSplitterDirection == GridSplitter.GridResizeDirection.Rows) - { - Window.Current.CoreWindow.PointerCursor = GridSplitter.RowSplitterCursor; - } - } - else - { - var coreCursor = (CoreCursorType)((int)_gripperCursor); - if (_gripperCursor == GridSplitter.GripperCursorType.Custom) - { - if (_gripperCustomCursorResource > GridSplitter.GripperCustomCursorDefaultResource) - { - Window.Current.CoreWindow.PointerCursor = new CoreCursor(coreCursor, (uint)_gripperCustomCursorResource); - } - } - else - { - Window.Current.CoreWindow.PointerCursor = new CoreCursor(coreCursor, 1); - } - } - } - - internal void SplitterManipulationStarted(object sender, ManipulationStartedRoutedEventArgs e) - { - var splitter = sender as GridSplitter; - if (splitter == null) - { - return; - } - - _splitterPreviousPointer = splitter.PreviousCursor; - _isDragging = true; - } - - internal void SplitterManipulationCompleted(object sender, ManipulationCompletedRoutedEventArgs e) - { - var splitter = sender as GridSplitter; - if (splitter == null) - { - return; - } - - Window.Current.CoreWindow.PointerCursor = splitter.PreviousCursor = _splitterPreviousPointer; - _isDragging = false; - } - - internal void UnhookEvents() - { - if (_element == null) - { - return; - } - - _element.PointerEntered -= Element_PointerEntered; - _element.PointerExited -= Element_PointerExited; - } - } -} \ No newline at end of file diff --git a/Microsoft.Toolkit.Uwp.UI.Controls.Layout/GridSplitter/SplitBase.cs b/Microsoft.Toolkit.Uwp.UI.Controls.Layout/GridSplitter/SplitBase.cs index 62aed6fa154..c46bd3a9b9f 100644 --- a/Microsoft.Toolkit.Uwp.UI.Controls.Layout/GridSplitter/SplitBase.cs +++ b/Microsoft.Toolkit.Uwp.UI.Controls.Layout/GridSplitter/SplitBase.cs @@ -2,14 +2,10 @@ // 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 System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; using Windows.UI.Core; using Windows.UI.Xaml; using Windows.UI.Xaml.Controls; +using Windows.UI.Xaml.Media; namespace Microsoft.Toolkit.Uwp.UI.Controls { @@ -48,6 +44,21 @@ public CoreCursorType GripperCursor public static readonly DependencyProperty GripperCursorProperty = DependencyProperty.Register(nameof(GripperCursor), typeof(CoreCursorType), typeof(SplitBase), new PropertyMetadata(CoreCursorType.SizeWestEast)); + /// + /// Gets or sets the foreground color of sizer grip. + /// + public Brush GripperForeground + { + get { return (Brush)GetValue(GripperForegroundProperty); } + set { SetValue(GripperForegroundProperty, value); } + } + + /// + /// Identifies the dependency property. + /// + public static readonly DependencyProperty GripperForegroundProperty = + DependencyProperty.Register(nameof(GripperForeground), typeof(Brush), typeof(SplitBase), new PropertyMetadata(default(Brush))); + /// /// Gets or sets the direction that the sizer will interact with. /// From e79bcbc97c3dd7055754f0f6f151aaffc407aecd Mon Sep 17 00:00:00 2001 From: Darren Batchelor Date: Fri, 14 Jan 2022 15:54:10 -0800 Subject: [PATCH 11/22] Further refactoring --- .../ContentSizer/ContentSizer.Events.cs | 2 - .../ContentSizer/ContentSizer.cs | 21 --------- .../ContentSizer/ContentSizer.xaml | 3 +- .../GridSplitter/GridSplitter.Events.cs | 6 +-- .../GridSplitter/SplitBase.cs | 47 ++++++++++++++++--- 5 files changed, 43 insertions(+), 36 deletions(-) diff --git a/Microsoft.Toolkit.Uwp.UI.Controls.Layout/ContentSizer/ContentSizer.Events.cs b/Microsoft.Toolkit.Uwp.UI.Controls.Layout/ContentSizer/ContentSizer.Events.cs index 8bb652e809d..6e94dcbfdf1 100644 --- a/Microsoft.Toolkit.Uwp.UI.Controls.Layout/ContentSizer/ContentSizer.Events.cs +++ b/Microsoft.Toolkit.Uwp.UI.Controls.Layout/ContentSizer/ContentSizer.Events.cs @@ -95,7 +95,6 @@ private bool VerticalMove(double verticalChange) return true; } - // TODO: This only works if splitter is on top and making things grow down // Do we need our ContentResizeDirection to be 4 way? Maybe 'Auto' would check the horizontal/vertical alignment of the target??? TargetControl.Height += verticalChange; @@ -118,7 +117,6 @@ private bool HorizontalMove(double horizontalChange) return true; } - // TODO: This only works if splitter is on left and making things grow right... TargetControl.Width += horizontalChange; GripperCursor = Windows.UI.Core.CoreCursorType.SizeWestEast; diff --git a/Microsoft.Toolkit.Uwp.UI.Controls.Layout/ContentSizer/ContentSizer.cs b/Microsoft.Toolkit.Uwp.UI.Controls.Layout/ContentSizer/ContentSizer.cs index 09377d6f148..35e6b322a10 100644 --- a/Microsoft.Toolkit.Uwp.UI.Controls.Layout/ContentSizer/ContentSizer.cs +++ b/Microsoft.Toolkit.Uwp.UI.Controls.Layout/ContentSizer/ContentSizer.cs @@ -17,27 +17,6 @@ namespace Microsoft.Toolkit.Uwp.UI.Controls [ContentProperty(Name = nameof(Content))] public partial class ContentSizer : SplitBase { - // Symbols for GripperBar in Segoe MDL2 Assets - private const string GripperBarVertical = "\xE784"; - private const string GripperBarHorizontal = "\xE76F"; - - private const double GripperKeyboardChange = 8.0d; - - /// - /// Gets or sets the content template for the . By default is a TextBlock. - /// - public DataTemplate ContentTemplate - { - get { return (DataTemplate)GetValue(ContentTemplateProperty); } - set { SetValue(ContentTemplateProperty, value); } - } - - /// - /// Identifies the dependency property. - /// - public static readonly DependencyProperty ContentTemplateProperty = - DependencyProperty.Register(nameof(ContentTemplate), typeof(DataTemplate), typeof(ContentSizer), new PropertyMetadata(null)); - /// /// Initializes a new instance of the class. /// diff --git a/Microsoft.Toolkit.Uwp.UI.Controls.Layout/ContentSizer/ContentSizer.xaml b/Microsoft.Toolkit.Uwp.UI.Controls.Layout/ContentSizer/ContentSizer.xaml index d5067a6fb89..5db5e04cf3e 100644 --- a/Microsoft.Toolkit.Uwp.UI.Controls.Layout/ContentSizer/ContentSizer.xaml +++ b/Microsoft.Toolkit.Uwp.UI.Controls.Layout/ContentSizer/ContentSizer.xaml @@ -1,8 +1,7 @@ - -