Skip to content

Commit 7c20776

Browse files
Initial staging/layout of ResizeElementAdorner
Have initial thumbs with cursor changing TODO: Resize...!
1 parent c7b1810 commit 7c20776

File tree

9 files changed

+305
-2
lines changed

9 files changed

+305
-2
lines changed
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<!-- 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. -->
2+
<Page x:Class="AdornersExperiment.Samples.ResizeElement.ResizeElementAdornerSample"
3+
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
4+
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
5+
xmlns:adorners="using:CommunityToolkit.WinUI.Adorners"
6+
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
7+
xmlns:local="using:AdornersExperiment.Samples.ResizeElement"
8+
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
9+
xmlns:muxc="using:Microsoft.UI.Xaml.Controls"
10+
xmlns:ui="using:CommunityToolkit.WinUI"
11+
mc:Ignorable="d">
12+
13+
<Canvas>
14+
<Rectangle Canvas.Left="150"
15+
Canvas.Top="150"
16+
Width="200"
17+
Height="100"
18+
Fill="Red">
19+
<ui:AdornerLayer.Xaml>
20+
<!-- TODO: Maybe have this be toggled based on a focus-based selection in the sample? -->
21+
<adorners:ResizeElementAdorner Visibility="{x:Bind IsAdornerVisible, Mode=OneWay}"/>
22+
</ui:AdornerLayer.Xaml>
23+
</Rectangle>
24+
</Canvas>
25+
</Page>
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
// See the LICENSE file in the project root for more information.
4+
5+
namespace AdornersExperiment.Samples.ResizeElement;
6+
7+
[ToolkitSampleBoolOption("IsAdornerVisible", false, Title = "Is Adorner Visible")]
8+
[ToolkitSample(id: nameof(ResizeElementAdornerSample), "Resize Element Adorner", description: "A sample for showing how to use an Adorner for resizing an element.")]
9+
public sealed partial class ResizeElementAdornerSample : Page
10+
{
11+
public ResizeElementAdornerSample()
12+
{
13+
this.InitializeComponent();
14+
}
15+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
---
2+
title: ResizeElementAdorner
3+
author: michael-hawker
4+
description: A ResizeElementAdorner provides resizing functionality to FrameworkElement.
5+
keywords: Adorners, Resize, FrameworkElement, Layout, Controls
6+
dev_langs:
7+
- csharp
8+
category: Controls
9+
subcategory: Layout
10+
discussion-id: 278
11+
issue-id: 0
12+
icon: assets/icon.png
13+
---
14+
15+
# ResizeElementAdorner
16+
17+
The `ResizeElementAdorner` provides resizing functionality to any `FrameworkElement`.
18+
19+
## Usage Example
20+
21+
The `ResizeElementAdorner` can be attached to any element and displayed to allow a user to resize the adorned element by dragging the resize handles.
22+
23+
> [!SAMPLE ResizeElementAdornerSample]
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
// See the LICENSE file in the project root for more information.
4+
5+
namespace CommunityToolkit.WinUI.Adorners;
6+
7+
/// <summary>
8+
/// An <see cref="Adorner"/> that will allow a user to resize the adorned element.
9+
/// </summary>
10+
public sealed partial class ResizeElementAdorner : Adorner<FrameworkElement>
11+
{
12+
/// <summary>
13+
/// Initializes a new instance of the <see cref="ResizeElementAdorner"/> class.
14+
/// </summary>
15+
public ResizeElementAdorner()
16+
{
17+
this.DefaultStyleKey = typeof(ResizeElementAdorner);
18+
19+
// Uno workaround
20+
DataContext = this;
21+
}
22+
23+
/// <inheritdoc/>
24+
protected override void OnApplyTemplate()
25+
{
26+
base.OnApplyTemplate();
27+
}
28+
29+
/// <inheritdoc/>
30+
protected override void OnAttached()
31+
{
32+
base.OnAttached();
33+
}
34+
35+
/// <inheritdoc/>
36+
protected override void OnDetaching()
37+
{
38+
base.OnDetaching();
39+
}
40+
}
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
<!-- 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. -->
2+
<ResourceDictionary x:Class="CommunityToolkit.WinUI.Adorners.Resources.ResizeElementAdornerResources"
3+
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
4+
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
5+
xmlns:adorners="using:CommunityToolkit.WinUI.Adorners"
6+
xmlns:controls="using:CommunityToolkit.WinUI.Controls"
7+
xmlns:ui="using:CommunityToolkit.WinUI">
8+
9+
<!-- Implicitly applied default style -->
10+
<Style BasedOn="{StaticResource DefaultResizeElementAdornerStyle}"
11+
TargetType="adorners:ResizeElementAdorner" />
12+
13+
<Style x:Key="DefaultResizeElementAdornerStyle"
14+
TargetType="adorners:ResizeElementAdorner">
15+
<Setter Property="Template">
16+
<Setter.Value>
17+
<ControlTemplate TargetType="adorners:ResizeElementAdorner">
18+
<ContentControl x:Name="ContentContainer"
19+
HorizontalContentAlignment="Stretch"
20+
VerticalContentAlignment="Stretch">
21+
<ContentControl.ContentTemplate>
22+
<DataTemplate x:DataType="adorners:ResizeElementAdorner">
23+
<Grid BorderBrush="{ThemeResource SurfaceStrokeColorDefaultBrush}"
24+
BorderThickness="1">
25+
<controls:ResizeThumb x:Name="PART_TopThumb"
26+
Margin="0,-8,0,0"
27+
HorizontalAlignment="Center"
28+
VerticalAlignment="Top"
29+
Cursor="SizeNorthSouth" />
30+
<controls:ResizeThumb x:Name="PART_BottomThumb"
31+
Margin="0,0,0,-8"
32+
HorizontalAlignment="Center"
33+
VerticalAlignment="Bottom"
34+
Cursor="SizeNorthSouth" />
35+
<controls:ResizeThumb x:Name="PART_LeftThumb"
36+
Margin="-8,0,0,0"
37+
HorizontalAlignment="Left"
38+
VerticalAlignment="Center"
39+
Cursor="SizeWestEast" />
40+
<controls:ResizeThumb x:Name="PART_RightThumb"
41+
Margin="0,0,-8,0"
42+
HorizontalAlignment="Right"
43+
VerticalAlignment="Center"
44+
Cursor="SizeWestEast" />
45+
<controls:ResizeThumb x:Name="PART_UpperLeftThumb"
46+
Margin="-8,-8,0,0"
47+
HorizontalAlignment="Left"
48+
VerticalAlignment="Top"
49+
Cursor="SizeNorthwestSoutheast" />
50+
<controls:ResizeThumb x:Name="PART_UpperRightThumb"
51+
Margin="0,-8,-8,0"
52+
HorizontalAlignment="Right"
53+
VerticalAlignment="Top"
54+
Cursor="SizeNortheastSouthwest" />
55+
<controls:ResizeThumb x:Name="PART_LowerLeftThumb"
56+
Margin="-8,0,0,-8"
57+
HorizontalAlignment="Left"
58+
VerticalAlignment="Bottom"
59+
Cursor="SizeNortheastSouthwest" />
60+
<controls:ResizeThumb x:Name="PART_LowerRightThumb"
61+
Margin="0,0,-8,-8"
62+
HorizontalAlignment="Right"
63+
VerticalAlignment="Bottom"
64+
Cursor="SizeNorthwestSoutheast" />
65+
</Grid>
66+
</DataTemplate>
67+
</ContentControl.ContentTemplate>
68+
</ContentControl>
69+
</ControlTemplate>
70+
</Setter.Value>
71+
</Setter>
72+
</Style>
73+
</ResourceDictionary>
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
// See the LICENSE file in the project root for more information.
4+
5+
namespace CommunityToolkit.WinUI.Adorners.Resources;
6+
7+
/// <summary>
8+
/// XAML resource dictionary for <see cref="ResizeElementAdorner"/>.
9+
/// </summary>
10+
public sealed partial class ResizeElementAdornerResources : ResourceDictionary
11+
{
12+
// NOTICE
13+
// This file only exists to enable x:Bind in the resource dictionary.
14+
// Do not add code here.
15+
// Instead, add code-behind to your templated control.
16+
17+
/// <summary>
18+
/// Initializes a new instance of the <see cref="ResizeElementAdornerResources"/> class.
19+
/// </summary>
20+
public ResizeElementAdornerResources()
21+
{
22+
this.InitializeComponent();
23+
}
24+
}
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
// See the LICENSE file in the project root for more information.
4+
5+
#if !WINAPPSDK
6+
using CursorEnum = Windows.UI.Core.CoreCursorType;
7+
#else
8+
using Microsoft.UI.Input;
9+
using CursorEnum = Microsoft.UI.Input.InputSystemCursorShape;
10+
#endif
11+
12+
namespace CommunityToolkit.WinUI.Controls;
13+
14+
/// <summary>
15+
/// A simple Thumb control which can be manipulated in multiple directions to assist with resize scenarios.
16+
/// </summary>
17+
public partial class ResizeThumb : Control
18+
{
19+
/// <summary>
20+
/// Gets or sets the cursor which should be displayed when the mouse is over this thumb.
21+
/// </summary>
22+
public CursorEnum Cursor
23+
{
24+
get { return (CursorEnum)GetValue(CursorProperty); }
25+
set { SetValue(CursorProperty, value); }
26+
}
27+
28+
/// <summary>
29+
/// Identifies the <see cref="Cursor"/> dependency property.
30+
/// </summary>
31+
public static readonly DependencyProperty CursorProperty =
32+
DependencyProperty.Register(nameof(Cursor), typeof(CursorEnum), typeof(ResizeThumb), new PropertyMetadata(null, OnCursorChanged));
33+
34+
private static void OnCursorChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
35+
{
36+
if (d is ResizeThumb resizeThumb)
37+
{
38+
#if !WINAPPSDK
39+
// On UWP, we use our XAML extension to control this behavior,
40+
// so we'll update it here (and maintain any cursor override).
41+
if (cursor is CursorEnum cursorValue)
42+
{
43+
FrameworkElementExtensions.SetCursor(gripper, cursorValue);
44+
}
45+
46+
return;
47+
#endif
48+
49+
#if WINUI3
50+
// On WinUI 3, we can set the ProtectedCursor directly.
51+
if (e.NewValue is CursorEnum cursorValue &&
52+
(resizeThumb.ProtectedCursor == null ||
53+
(resizeThumb.ProtectedCursor is InputSystemCursor current &&
54+
current.CursorShape != cursorValue)))
55+
{
56+
resizeThumb.ProtectedCursor = InputSystemCursor.Create(cursorValue);
57+
}
58+
#endif
59+
}
60+
}
61+
62+
/// <inheritdoc/>
63+
public ResizeThumb()
64+
{
65+
this.DefaultStyleKey = typeof(ResizeThumb);
66+
}
67+
68+
protected override void OnApplyTemplate()
69+
{
70+
base.OnApplyTemplate();
71+
}
72+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
2+
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
3+
xmlns:controls="using:CommunityToolkit.WinUI.Controls">
4+
5+
<!-- Implicitly applied default style -->
6+
<Style BasedOn="{StaticResource DefaultResizeThumbStyle}"
7+
TargetType="controls:ResizeThumb" />
8+
9+
<Style x:Key="DefaultResizeThumbStyle"
10+
TargetType="controls:ResizeThumb">
11+
<Setter Property="IsTabStop" Value="True" />
12+
<Setter Property="UseSystemFocusVisuals" Value="True" />
13+
<Setter Property="Width" Value="16" />
14+
<Setter Property="Height" Value="16" />
15+
<Setter Property="Background" Value="{ThemeResource SystemControlBackgroundChromeWhiteBrush}" />
16+
<Setter Property="BorderBrush" Value="{ThemeResource SystemControlForegroundChromeHighBrush}" />
17+
<Setter Property="BorderThickness" Value="1" />
18+
<Setter Property="Template">
19+
<Setter.Value>
20+
<ControlTemplate TargetType="controls:ResizeThumb">
21+
<Border Background="{TemplateBinding Background}"
22+
BorderBrush="{TemplateBinding BorderBrush}"
23+
BorderThickness="{TemplateBinding BorderThickness}"
24+
CornerRadius="8" />
25+
</ControlTemplate>
26+
</Setter.Value>
27+
</Setter>
28+
</Style>
29+
</ResourceDictionary>
Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
1+
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
22
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
33
xmlns:resources="using:CommunityToolkit.WinUI.Adorners.Resources">
44
<ResourceDictionary.MergedDictionaries>
@@ -7,6 +7,8 @@
77
<ResourceDictionary Source="ms-appx:///CommunityToolkit.WinUI.Adorners/AdornerDecorator.xaml" />
88

99
<!-- Custom Adorners -->
10-
<resources:InputValidationAdornerResources xmlns:adorners="using:CommunityToolkit.WinUI.Adorners" />
10+
<resources:InputValidationAdornerResources />
11+
<ResourceDictionary Source="ms-appx:///CommunityToolkit.WinUI.Adorners/ResizeElement/ResizeThumb.xaml" />
12+
<resources:ResizeElementAdornerResources />
1113
</ResourceDictionary.MergedDictionaries>
1214
</ResourceDictionary>

0 commit comments

Comments
 (0)