From b3edfe80ef6a5729ec1d9877cf370080ee7a867b Mon Sep 17 00:00:00 2001
From: qian-o <1324771795@qq.com>
Date: Tue, 27 May 2025 02:46:11 +0800
Subject: [PATCH 1/2] Adjust the definition of Size.Empty to use (0,0) to
represent an empty layout in layout calculations, and improve the
TemplatePart attribute to ensure proper functionality after AOT publishing.
---
.../src/LayoutTransformControl.cs | 17 ++++++++++-------
1 file changed, 10 insertions(+), 7 deletions(-)
diff --git a/components/LayoutTransformControl/src/LayoutTransformControl.cs b/components/LayoutTransformControl/src/LayoutTransformControl.cs
index 85879e09..fd6f489e 100644
--- a/components/LayoutTransformControl/src/LayoutTransformControl.cs
+++ b/components/LayoutTransformControl/src/LayoutTransformControl.cs
@@ -9,9 +9,12 @@ namespace CommunityToolkit.WinUI.Controls;
/// Control that implements support for transformations as if applied by LayoutTransform.
///
[ContentProperty(Name = "Child")]
-
+[TemplatePart(Name = "LayoutRoot", Type = typeof(Panel))]
+[TemplatePart(Name = "MatrixTransform", Type = typeof(MatrixTransform))]
public partial class LayoutTransformControl : Control
{
+ private static Size EmptySize => new Size();
+
///
/// Value used to work around double arithmetic rounding issues.
///
@@ -45,7 +48,7 @@ public partial class LayoutTransformControl : Control
///
/// Actual DesiredSize of Child element.
///
- private Size _childActualSize = Size.Empty;
+ private Size _childActualSize = EmptySize;
///
/// Initializes a new instance of the class.
@@ -235,11 +238,11 @@ protected override Size MeasureOverride(Size availableSize)
if (_layoutRoot == null || child == null)
{
// No content, no size
- return Size.Empty;
+ return EmptySize;
}
Size measureSize;
- if (_childActualSize == Size.Empty)
+ if (_childActualSize == EmptySize)
{
// Determine the largest size after the transformation
measureSize = ComputeLargestTransformedSize(availableSize);
@@ -301,7 +304,7 @@ protected override Size ArrangeOverride(Size finalSize)
_layoutRoot.Arrange(finalRect);
// This is the first opportunity to find out the Child's true DesiredSize
- if (IsSizeSmaller(finalSizeTransformed, child.RenderSize) && (Size.Empty == _childActualSize))
+ if (IsSizeSmaller(finalSizeTransformed, child.RenderSize) && (EmptySize == _childActualSize))
{
// Unfortunately, all the work so far is invalid because the wrong DesiredSize was used
// Make a note of the actual DesiredSize
@@ -313,7 +316,7 @@ protected override Size ArrangeOverride(Size finalSize)
else
{
// Clear the "need to measure/arrange again" flag
- _childActualSize = Size.Empty;
+ _childActualSize = EmptySize;
}
// Return result to perform the transformation
@@ -329,7 +332,7 @@ protected override Size ArrangeOverride(Size finalSize)
private Size ComputeLargestTransformedSize(Size arrangeBounds)
{
// Computed largest transformed size
- Size computedSize = Size.Empty;
+ Size computedSize = EmptySize;
// Detect infinite bounds and constrain the scenario
bool infiniteWidth = double.IsInfinity(arrangeBounds.Width);
From 84e39852f539750ea69d25dd81e69a23450985cd Mon Sep 17 00:00:00 2001
From: qian-o <1324771795@qq.com>
Date: Tue, 27 May 2025 09:38:27 +0800
Subject: [PATCH 2/2] Simplify the listening of dependency properties.
---
.../src/LayoutTransformControl.Properties.cs | 13 ++--
.../src/PropertyChangeEventSource.cs | 77 ++++---------------
2 files changed, 21 insertions(+), 69 deletions(-)
diff --git a/components/LayoutTransformControl/src/LayoutTransformControl.Properties.cs b/components/LayoutTransformControl/src/LayoutTransformControl.Properties.cs
index 692476e4..0cbb79a4 100644
--- a/components/LayoutTransformControl/src/LayoutTransformControl.Properties.cs
+++ b/components/LayoutTransformControl/src/LayoutTransformControl.Properties.cs
@@ -127,6 +127,7 @@ private void UnsubscribeFromTransformPropertyChanges(Transform transform)
foreach (var propertyChangeEventSource in propertyChangeEventSources)
{
propertyChangeEventSource.ValueChanged -= OnTransformPropertyChanged;
+ propertyChangeEventSource.Unregister();
}
_transformPropertyChangeEventSources.Remove(transform);
@@ -153,7 +154,7 @@ private void SubscribeToTransformPropertyChanges(Transform transform)
if (rotateTransform != null)
{
- var anglePropertyChangeEventSource = new PropertyChangeEventSource(rotateTransform, "Angle");
+ var anglePropertyChangeEventSource = new PropertyChangeEventSource(rotateTransform, RotateTransform.AngleProperty);
anglePropertyChangeEventSource.ValueChanged += OnTransformPropertyChanged;
propertyChangeEventSources.Add(anglePropertyChangeEventSource);
return;
@@ -163,11 +164,11 @@ private void SubscribeToTransformPropertyChanges(Transform transform)
if (scaleTransform != null)
{
- var scaleXPropertyChangeEventSource = new PropertyChangeEventSource(scaleTransform, "ScaleX");
+ var scaleXPropertyChangeEventSource = new PropertyChangeEventSource(scaleTransform, ScaleTransform.ScaleXProperty);
scaleXPropertyChangeEventSource.ValueChanged += OnTransformPropertyChanged;
propertyChangeEventSources.Add(scaleXPropertyChangeEventSource);
- var scaleYPropertyChangeEventSource = new PropertyChangeEventSource(scaleTransform, "ScaleY");
+ var scaleYPropertyChangeEventSource = new PropertyChangeEventSource(scaleTransform, ScaleTransform.ScaleYProperty);
scaleYPropertyChangeEventSource.ValueChanged += OnTransformPropertyChanged;
propertyChangeEventSources.Add(scaleYPropertyChangeEventSource);
return;
@@ -177,11 +178,11 @@ private void SubscribeToTransformPropertyChanges(Transform transform)
if (skewTransform != null)
{
- var angleXPropertyChangeEventSource = new PropertyChangeEventSource(skewTransform, "AngleX");
+ var angleXPropertyChangeEventSource = new PropertyChangeEventSource(skewTransform, SkewTransform.AngleXProperty);
angleXPropertyChangeEventSource.ValueChanged += OnTransformPropertyChanged;
propertyChangeEventSources.Add(angleXPropertyChangeEventSource);
- var angleYPropertyChangeEventSource = new PropertyChangeEventSource(skewTransform, "AngleY");
+ var angleYPropertyChangeEventSource = new PropertyChangeEventSource(skewTransform, SkewTransform.AngleYProperty);
angleYPropertyChangeEventSource.ValueChanged += OnTransformPropertyChanged;
propertyChangeEventSources.Add(angleYPropertyChangeEventSource);
return;
@@ -194,7 +195,7 @@ private void SubscribeToTransformPropertyChanges(Transform transform)
var matrixPropertyChangeEventSource =
new PropertyChangeEventSource(
matrixTransform,
- "Matrix");
+ MatrixTransform.MatrixProperty);
matrixPropertyChangeEventSource.ValueChanged += OnTransformPropertyChanged;
propertyChangeEventSources.Add(matrixPropertyChangeEventSource);
}
diff --git a/components/LayoutTransformControl/src/PropertyChangeEventSource.cs b/components/LayoutTransformControl/src/PropertyChangeEventSource.cs
index 9ea384c6..ac141b06 100644
--- a/components/LayoutTransformControl/src/PropertyChangeEventSource.cs
+++ b/components/LayoutTransformControl/src/PropertyChangeEventSource.cs
@@ -8,87 +8,38 @@ namespace CommunityToolkit.WinUI.Controls;
/// Allows raise an event when the value of a dependency property changes when a view model is otherwise not necessary.
///
/// Type of the DependencyProperty
-internal partial class PropertyChangeEventSource : FrameworkElement
+internal partial class PropertyChangeEventSource
{
private readonly DependencyObject _source;
+ private readonly DependencyProperty _property;
+ private readonly long _token;
///
/// Occurs when the value changes.
///
public event EventHandler ValueChanged;
- ///
- /// Value Dependency Property
- ///
- public static readonly DependencyProperty ValueProperty =
- DependencyProperty.Register(
- "Value",
- typeof(TPropertyType),
- typeof(PropertyChangeEventSource),
- new PropertyMetadata(default(TPropertyType), OnValueChanged));
-
- ///
- /// Gets or sets the Value property. This dependency property
- /// indicates the value.
- ///
- public TPropertyType Value
- {
- get { return (TPropertyType)GetValue(ValueProperty); }
- set { SetValue(ValueProperty, value); }
- }
-
- ///
- /// Handles changes to the Value property.
- ///
- ///
- /// The on which the property has changed value.
- ///
- ///
- /// Event data that is issued by any event that
- /// tracks changes to the effective value of this property.
- ///
- private static void OnValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
- {
- var target = (PropertyChangeEventSource)d;
- TPropertyType oldValue = (TPropertyType)e.OldValue;
- TPropertyType newValue = target.Value;
- target.OnValueChanged(oldValue, newValue);
- }
-
- ///
- /// Provides derived classes an opportunity to handle changes to the Value property.
- ///
- /// The old Value value
- /// The new Value value
- private void OnValueChanged(TPropertyType oldValue, TPropertyType newValue)
- {
- ValueChanged?.Invoke(_source, newValue);
- }
-
///
/// Initializes a new instance of the class.
///
/// The source.
- /// Name of the property.
- /// The binding mode.
+ /// Monitor this dependency property for changes.
#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable.
public PropertyChangeEventSource(
#pragma warning restore CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable.
DependencyObject source,
- string propertyName,
- BindingMode bindingMode = BindingMode.TwoWay)
+ DependencyProperty property)
{
_source = source;
+ _property = property;
+ _token = source.RegisterPropertyChangedCallback(property, (_, _) =>
+ {
+ ValueChanged?.Invoke(this, (TPropertyType)source.GetValue(property));
+ });
+ }
- // Bind to the property to be able to get its changes relayed as events through the ValueChanged event.
- var binding =
- new Binding
- {
- Source = source,
- Path = new PropertyPath(propertyName),
- Mode = bindingMode
- };
-
- SetBinding(ValueProperty, binding);
+ public void Unregister()
+ {
+ _source.UnregisterPropertyChangedCallback(_property, _token);
}
}