diff --git a/samples/IntegrationTestApp/MainWindow.axaml b/samples/IntegrationTestApp/MainWindow.axaml
index a6f463fdcb..353e01dca7 100644
--- a/samples/IntegrationTestApp/MainWindow.axaml
+++ b/samples/IntegrationTestApp/MainWindow.axaml
@@ -153,6 +153,9 @@
+
+
+
diff --git a/src/Avalonia.Base/AvaloniaObject.cs b/src/Avalonia.Base/AvaloniaObject.cs
index 2c9efc7767..d89d6f3690 100644
--- a/src/Avalonia.Base/AvaloniaObject.cs
+++ b/src/Avalonia.Base/AvaloniaObject.cs
@@ -664,14 +664,12 @@ namespace Avalonia
/// The property that has changed.
/// The old property value.
/// The new property value.
- /// The priority of the binding that produced the value.
protected void RaisePropertyChanged(
DirectPropertyBase property,
- Optional oldValue,
- BindingValue newValue,
- BindingPriority priority = BindingPriority.LocalValue)
+ T oldValue,
+ T newValue)
{
- RaisePropertyChanged(property, oldValue, newValue, priority, true);
+ RaisePropertyChanged(property, oldValue, newValue, BindingPriority.LocalValue, true);
}
///
@@ -720,7 +718,7 @@ namespace Avalonia
///
/// True if the value changed, otherwise false.
///
- protected bool SetAndRaise(AvaloniaProperty property, ref T field, T value)
+ protected bool SetAndRaise(DirectPropertyBase property, ref T field, T value)
{
VerifyAccess();
diff --git a/src/Avalonia.Base/Data/Core/IndexerNodeBase.cs b/src/Avalonia.Base/Data/Core/IndexerNodeBase.cs
index 9ec256225b..57e4fa4a8e 100644
--- a/src/Avalonia.Base/Data/Core/IndexerNodeBase.cs
+++ b/src/Avalonia.Base/Data/Core/IndexerNodeBase.cs
@@ -22,7 +22,7 @@ namespace Avalonia.Data.Core
if (target is INotifyPropertyChanged inpc)
{
- WeakEvents.PropertyChanged.Subscribe(inpc, this);
+ WeakEvents.ThreadSafePropertyChanged.Subscribe(inpc, this);
}
ValueChanged(GetValue(target));
@@ -39,7 +39,7 @@ namespace Avalonia.Data.Core
if (target is INotifyPropertyChanged inpc)
{
- WeakEvents.PropertyChanged.Unsubscribe(inpc, this);
+ WeakEvents.ThreadSafePropertyChanged.Unsubscribe(inpc, this);
}
}
}
diff --git a/src/Avalonia.Base/Data/Core/Plugins/InpcPropertyAccessorPlugin.cs b/src/Avalonia.Base/Data/Core/Plugins/InpcPropertyAccessorPlugin.cs
index 7c2caf02b4..e8e3e6d509 100644
--- a/src/Avalonia.Base/Data/Core/Plugins/InpcPropertyAccessorPlugin.cs
+++ b/src/Avalonia.Base/Data/Core/Plugins/InpcPropertyAccessorPlugin.cs
@@ -160,7 +160,7 @@ namespace Avalonia.Data.Core.Plugins
var inpc = GetReferenceTarget() as INotifyPropertyChanged;
if (inpc != null)
- WeakEvents.PropertyChanged.Unsubscribe(inpc, this);
+ WeakEvents.ThreadSafePropertyChanged.Unsubscribe(inpc, this);
}
private object? GetReferenceTarget()
@@ -185,7 +185,7 @@ namespace Avalonia.Data.Core.Plugins
var inpc = GetReferenceTarget() as INotifyPropertyChanged;
if (inpc != null)
- WeakEvents.PropertyChanged.Subscribe(inpc, this);
+ WeakEvents.ThreadSafePropertyChanged.Subscribe(inpc, this);
}
}
}
diff --git a/src/Avalonia.Base/Layout/LayoutInformation.cs b/src/Avalonia.Base/Layout/LayoutInformation.cs
new file mode 100644
index 0000000000..9b821053a2
--- /dev/null
+++ b/src/Avalonia.Base/Layout/LayoutInformation.cs
@@ -0,0 +1,27 @@
+namespace Avalonia.Layout;
+
+///
+/// Provides access to layout information of a control.
+///
+public static class LayoutInformation
+{
+ ///
+ /// Gets the available size constraint passed in the previous layout pass.
+ ///
+ /// The control.
+ /// Previous control measure constraint, if any.
+ public static Size? GetPreviousMeasureConstraint(Layoutable control)
+ {
+ return control.PreviousMeasure;
+ }
+
+ ///
+ /// Gets the control bounds used in the previous layout arrange pass.
+ ///
+ /// The control.
+ /// Previous control arrange bounds, if any.
+ public static Rect? GetPreviousArrangeBounds(Layoutable control)
+ {
+ return control.PreviousArrange;
+ }
+}
diff --git a/src/Avalonia.Base/Layout/Layoutable.cs b/src/Avalonia.Base/Layout/Layoutable.cs
index 775b8adddd..4a273b0291 100644
--- a/src/Avalonia.Base/Layout/Layoutable.cs
+++ b/src/Avalonia.Base/Layout/Layoutable.cs
@@ -323,6 +323,9 @@ namespace Avalonia.Layout
set { SetValue(UseLayoutRoundingProperty, value); }
}
+ ///
+ /// Gets the available size passed in the previous layout pass, if any.
+ ///
internal Size? PreviousMeasure => _previousMeasure;
///
diff --git a/src/Avalonia.Base/Rendering/Composition/Server/ServerCompositionVisual.cs b/src/Avalonia.Base/Rendering/Composition/Server/ServerCompositionVisual.cs
index e33dc999dc..98be861afa 100644
--- a/src/Avalonia.Base/Rendering/Composition/Server/ServerCompositionVisual.cs
+++ b/src/Avalonia.Base/Rendering/Composition/Server/ServerCompositionVisual.cs
@@ -48,7 +48,8 @@ namespace Avalonia.Rendering.Composition.Server
{
canvas.PostTransform = Matrix.Identity;
canvas.Transform = Matrix.Identity;
- canvas.PushClip(AdornedVisual._combinedTransformedClipBounds);
+ if (AdornerIsClipped)
+ canvas.PushClip(AdornedVisual._combinedTransformedClipBounds);
}
var transform = GlobalTransformMatrix;
canvas.PostTransform = MatrixUtils.ToMatrix(transform);
@@ -74,7 +75,7 @@ namespace Avalonia.Rendering.Composition.Server
canvas.PopGeometryClip();
if (ClipToBounds && !HandlesClipToBounds)
canvas.PopClip();
- if (AdornedVisual != null)
+ if (AdornedVisual != null && AdornerIsClipped)
canvas.PopClip();
if(Opacity != 1)
canvas.PopOpacity();
diff --git a/src/Avalonia.Base/StyledElement.cs b/src/Avalonia.Base/StyledElement.cs
index 2cdb973174..5b8dac2f53 100644
--- a/src/Avalonia.Base/StyledElement.cs
+++ b/src/Avalonia.Base/StyledElement.cs
@@ -524,13 +524,7 @@ namespace Avalonia
NotifyResourcesChanged();
}
-#nullable disable
- RaisePropertyChanged(
- ParentProperty,
- new Optional(old),
- new BindingValue(Parent),
- BindingPriority.LocalValue);
-#nullable enable
+ RaisePropertyChanged(ParentProperty, old, Parent);
}
}
diff --git a/src/Avalonia.Base/Utilities/WeakEvents.cs b/src/Avalonia.Base/Utilities/WeakEvents.cs
index 6da899bab2..2f62564e0e 100644
--- a/src/Avalonia.Base/Utilities/WeakEvents.cs
+++ b/src/Avalonia.Base/Utilities/WeakEvents.cs
@@ -2,6 +2,7 @@ using System;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Windows.Input;
+using Avalonia.Threading;
namespace Avalonia.Utilities;
@@ -20,15 +21,30 @@ public class WeakEvents
});
///
- /// Represents PropertyChanged event from
+ /// Represents PropertyChanged event from with auto-dispatching to the UI thread
///
public static readonly WeakEvent
- PropertyChanged = WeakEvent.Register(
+ ThreadSafePropertyChanged = WeakEvent.Register(
(s, h) =>
{
- PropertyChangedEventHandler handler = (_, e) => h(s, e);
+ bool unsubscribed = false;
+ PropertyChangedEventHandler handler = (_, e) =>
+ {
+ if (Dispatcher.UIThread.CheckAccess())
+ h(s, e);
+ else
+ Dispatcher.UIThread.Post(() =>
+ {
+ if (!unsubscribed)
+ h(s, e);
+ });
+ };
s.PropertyChanged += handler;
- return () => s.PropertyChanged -= handler;
+ return () =>
+ {
+ unsubscribed = true;
+ s.PropertyChanged -= handler;
+ };
});
diff --git a/src/Avalonia.Base/Visual.cs b/src/Avalonia.Base/Visual.cs
index 87bb1d3790..8b0cc06136 100644
--- a/src/Avalonia.Base/Visual.cs
+++ b/src/Avalonia.Base/Visual.cs
@@ -573,7 +573,7 @@ namespace Avalonia
/// The new visual parent.
protected virtual void OnVisualParentChanged(Visual? oldParent, Visual? newParent)
{
- RaisePropertyChanged(VisualParentProperty, oldParent, newParent, BindingPriority.LocalValue);
+ RaisePropertyChanged(VisualParentProperty, oldParent, newParent);
}
internal override ParametrizedLogger? GetBindingWarningLogger(
diff --git a/src/Avalonia.Base/composition-schema.xml b/src/Avalonia.Base/composition-schema.xml
index 36fd9fe709..31722974ee 100644
--- a/src/Avalonia.Base/composition-schema.xml
+++ b/src/Avalonia.Base/composition-schema.xml
@@ -26,6 +26,7 @@
+
diff --git a/src/Avalonia.Controls/Automation/Peers/SliderAutomationPeer.cs b/src/Avalonia.Controls/Automation/Peers/SliderAutomationPeer.cs
new file mode 100644
index 0000000000..42b15eec96
--- /dev/null
+++ b/src/Avalonia.Controls/Automation/Peers/SliderAutomationPeer.cs
@@ -0,0 +1,22 @@
+using Avalonia.Automation.Peers;
+
+namespace Avalonia.Controls.Automation.Peers
+{
+ public class SliderAutomationPeer : RangeBaseAutomationPeer
+ {
+ public SliderAutomationPeer(Slider owner) : base(owner)
+ {
+ }
+
+ override protected string GetClassNameCore()
+ {
+ return "Slider";
+ }
+
+ override protected AutomationControlType GetAutomationControlTypeCore()
+ {
+ return AutomationControlType.Slider;
+ }
+
+ }
+}
diff --git a/src/Avalonia.Controls/Primitives/AdornerLayer.cs b/src/Avalonia.Controls/Primitives/AdornerLayer.cs
index 79719912ea..611d57a980 100644
--- a/src/Avalonia.Controls/Primitives/AdornerLayer.cs
+++ b/src/Avalonia.Controls/Primitives/AdornerLayer.cs
@@ -279,8 +279,11 @@ namespace Avalonia.Controls.Primitives
private void UpdateAdornedElement(Visual adorner, Visual? adorned)
{
if (adorner.CompositionVisual != null)
+ {
adorner.CompositionVisual.AdornedVisual = adorned?.CompositionVisual;
-
+ adorner.CompositionVisual.AdornerIsClipped = GetIsClipEnabled(adorner);
+ }
+
var info = adorner.GetValue(s_adornedElementInfoProperty);
if (info != null)
diff --git a/src/Avalonia.Controls/Primitives/SelectingItemsControl.cs b/src/Avalonia.Controls/Primitives/SelectingItemsControl.cs
index 065c4ff2e5..2ee32b0dda 100644
--- a/src/Avalonia.Controls/Primitives/SelectingItemsControl.cs
+++ b/src/Avalonia.Controls/Primitives/SelectingItemsControl.cs
@@ -345,10 +345,7 @@ namespace Avalonia.Controls.Primitives
if (_oldSelectedItems != SelectedItems)
{
- RaisePropertyChanged(
- SelectedItemsProperty,
- new Optional(_oldSelectedItems),
- new BindingValue(SelectedItems));
+ RaisePropertyChanged(SelectedItemsProperty, _oldSelectedItems, SelectedItems);
_oldSelectedItems = SelectedItems;
}
}
@@ -909,10 +906,7 @@ namespace Avalonia.Controls.Primitives
else if (e.PropertyName == nameof(InternalSelectionModel.WritableSelectedItems) &&
_oldSelectedItems != (Selection as InternalSelectionModel)?.SelectedItems)
{
- RaisePropertyChanged(
- SelectedItemsProperty,
- new Optional(_oldSelectedItems),
- new BindingValue(SelectedItems));
+ RaisePropertyChanged(SelectedItemsProperty, _oldSelectedItems, SelectedItems);
_oldSelectedItems = SelectedItems;
}
else if (e.PropertyName == nameof(ISelectionModel.Source))
diff --git a/src/Avalonia.Controls/RelativePanel.AttachedProperties.cs b/src/Avalonia.Controls/RelativePanel.AttachedProperties.cs
index 18cf96ddca..d2b91def7d 100644
--- a/src/Avalonia.Controls/RelativePanel.AttachedProperties.cs
+++ b/src/Avalonia.Controls/RelativePanel.AttachedProperties.cs
@@ -1,37 +1,30 @@
using Avalonia.Layout;
+using Avalonia.Threading;
namespace Avalonia.Controls
{
public partial class RelativePanel
{
- private static void OnAlignPropertiesChanged(AvaloniaObject d, AvaloniaPropertyChangedEventArgs e)
- {
- if (d is Layoutable layoutable && layoutable.Parent is Layoutable layoutableParent)
- {
- layoutableParent.InvalidateArrange();
- }
- }
static RelativePanel()
{
ClipToBoundsProperty.OverrideDefaultValue(true);
- AboveProperty.Changed.AddClassHandler(OnAlignPropertiesChanged);
- AlignBottomWithPanelProperty.Changed.AddClassHandler(OnAlignPropertiesChanged);
- AlignBottomWithProperty.Changed.AddClassHandler(OnAlignPropertiesChanged);
- AlignHorizontalCenterWithPanelProperty.Changed.AddClassHandler(OnAlignPropertiesChanged);
- AlignHorizontalCenterWithProperty.Changed.AddClassHandler(OnAlignPropertiesChanged);
- AlignLeftWithPanelProperty.Changed.AddClassHandler(OnAlignPropertiesChanged);
- AlignLeftWithProperty.Changed.AddClassHandler(OnAlignPropertiesChanged);
- AlignRightWithPanelProperty.Changed.AddClassHandler(OnAlignPropertiesChanged);
- AlignRightWithProperty.Changed.AddClassHandler(OnAlignPropertiesChanged);
- AlignTopWithPanelProperty.Changed.AddClassHandler(OnAlignPropertiesChanged);
- AlignTopWithProperty.Changed.AddClassHandler(OnAlignPropertiesChanged);
- AlignVerticalCenterWithPanelProperty.Changed.AddClassHandler(OnAlignPropertiesChanged);
- AlignVerticalCenterWithProperty.Changed.AddClassHandler(OnAlignPropertiesChanged);
- BelowProperty.Changed.AddClassHandler(OnAlignPropertiesChanged);
- LeftOfProperty.Changed.AddClassHandler(OnAlignPropertiesChanged);
- RightOfProperty.Changed.AddClassHandler(OnAlignPropertiesChanged);
+ AffectsParentArrange(
+ AlignLeftWithPanelProperty, AlignLeftWithProperty, LeftOfProperty,
+ AlignRightWithPanelProperty, AlignRightWithProperty, RightOfProperty,
+ AlignTopWithPanelProperty, AlignTopWithProperty, AboveProperty,
+ AlignBottomWithPanelProperty, AlignBottomWithProperty, BelowProperty,
+ AlignHorizontalCenterWithPanelProperty, AlignHorizontalCenterWithProperty,
+ AlignVerticalCenterWithPanelProperty, AlignVerticalCenterWithProperty);
+
+ AffectsParentMeasure(
+ AlignLeftWithPanelProperty, AlignLeftWithProperty, LeftOfProperty,
+ AlignRightWithPanelProperty, AlignRightWithProperty, RightOfProperty,
+ AlignTopWithPanelProperty, AlignTopWithProperty, AboveProperty,
+ AlignBottomWithPanelProperty, AlignBottomWithProperty, BelowProperty,
+ AlignHorizontalCenterWithPanelProperty, AlignHorizontalCenterWithProperty,
+ AlignVerticalCenterWithPanelProperty, AlignVerticalCenterWithProperty);
}
///
diff --git a/src/Avalonia.Controls/Slider.cs b/src/Avalonia.Controls/Slider.cs
index 828bf2a1fb..7de726a932 100644
--- a/src/Avalonia.Controls/Slider.cs
+++ b/src/Avalonia.Controls/Slider.cs
@@ -10,6 +10,7 @@ using Avalonia.Interactivity;
using Avalonia.Layout;
using Avalonia.Utilities;
using Avalonia.Automation;
+using Avalonia.Controls.Automation.Peers;
namespace Avalonia.Controls
{
@@ -380,6 +381,11 @@ namespace Avalonia.Controls
}
}
+ protected override AutomationPeer OnCreateAutomationPeer()
+ {
+ return new SliderAutomationPeer(this);
+ }
+
///
protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
{
diff --git a/src/Avalonia.Diagnostics/Diagnostics/Controls/FilterTextBox.axaml b/src/Avalonia.Diagnostics/Diagnostics/Controls/FilterTextBox.axaml
index 3bfe511fbc..1b5f431f36 100644
--- a/src/Avalonia.Diagnostics/Diagnostics/Controls/FilterTextBox.axaml
+++ b/src/Avalonia.Diagnostics/Diagnostics/Controls/FilterTextBox.axaml
@@ -16,6 +16,8 @@