diff --git a/src/Avalonia.Controls/ComboBox.cs b/src/Avalonia.Controls/ComboBox.cs
index cbf9b35a05..05be5ad00d 100644
--- a/src/Avalonia.Controls/ComboBox.cs
+++ b/src/Avalonia.Controls/ComboBox.cs
@@ -181,26 +181,13 @@ namespace Avalonia.Controls
protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e)
{
base.OnAttachedToVisualTree(e);
- this.UpdateSelectionBoxItem(SelectedItem);
+ UpdateSelectionBoxItem(SelectedItem);
}
- // Because the SelectedItem isn't connected to the visual tree
public override void InvalidateMirrorTransform()
{
base.InvalidateMirrorTransform();
-
- if (SelectedItem is Control selectedControl)
- {
- selectedControl.InvalidateMirrorTransform();
-
- foreach (var visual in selectedControl.GetVisualDescendants())
- {
- if (visual is Control childControl)
- {
- childControl.InvalidateMirrorTransform();
- }
- }
- }
+ UpdateFlowDirection();
}
///
@@ -365,6 +352,8 @@ namespace Avalonia.Controls
{
parent.GetObservable(IsVisibleProperty).Subscribe(IsVisibleChanged).DisposeWith(_subscriptionsOnOpen);
}
+
+ UpdateFlowDirection();
}
private void IsVisibleChanged(bool isVisible)
@@ -432,6 +421,8 @@ namespace Avalonia.Controls
}
};
}
+
+ UpdateFlowDirection();
}
else
{
@@ -439,6 +430,19 @@ namespace Avalonia.Controls
}
}
+ private void UpdateFlowDirection()
+ {
+ if (SelectionBoxItem is Rectangle rectangle)
+ {
+ if ((rectangle.Fill as VisualBrush)?.Visual is Control content)
+ {
+ var flowDirection = (((IVisual)content!).VisualParent as Control)?.FlowDirection ??
+ FlowDirection.LeftToRight;
+ rectangle.FlowDirection = flowDirection;
+ }
+ }
+ }
+
private void SelectFocusedItem()
{
foreach (ItemContainerInfo dropdownItem in ItemContainerGenerator.Containers)
diff --git a/src/Avalonia.Controls/Control.cs b/src/Avalonia.Controls/Control.cs
index d6a5fa0727..16d4ef5c15 100644
--- a/src/Avalonia.Controls/Control.cs
+++ b/src/Avalonia.Controls/Control.cs
@@ -378,17 +378,12 @@ namespace Avalonia.Controls
bool bypassFlowDirectionPolicies = BypassFlowDirectionPolicies;
bool parentBypassFlowDirectionPolicies = false;
- var parent = this.FindAncestorOfType();
+ var parent = ((IVisual)this).VisualParent as Control;
if (parent != null)
{
parentFlowDirection = parent.FlowDirection;
parentBypassFlowDirectionPolicies = parent.BypassFlowDirectionPolicies;
}
- else if (Parent is Control logicalParent)
- {
- parentFlowDirection = logicalParent.FlowDirection;
- parentBypassFlowDirectionPolicies = logicalParent.BypassFlowDirectionPolicies;
- }
bool thisShouldBeMirrored = flowDirection == FlowDirection.RightToLeft && !bypassFlowDirectionPolicies;
bool parentShouldBeMirrored = parentFlowDirection == FlowDirection.RightToLeft && !parentBypassFlowDirectionPolicies;
diff --git a/tests/Avalonia.Base.UnitTests/Rendering/SceneGraph/SceneBuilderTests.cs b/tests/Avalonia.Base.UnitTests/Rendering/SceneGraph/SceneBuilderTests.cs
index 01afe85b8b..5cc9f57c8e 100644
--- a/tests/Avalonia.Base.UnitTests/Rendering/SceneGraph/SceneBuilderTests.cs
+++ b/tests/Avalonia.Base.UnitTests/Rendering/SceneGraph/SceneBuilderTests.cs
@@ -349,6 +349,39 @@ namespace Avalonia.Base.UnitTests.Rendering.SceneGraph
}
}
+ [Fact]
+ public void MirrorTransform_For_Control_With_RenderTransform_Should_Be_Correct()
+ {
+ using (UnitTestApplication.Start(TestServices.MockPlatformRenderInterface))
+ {
+ Border border;
+ var tree = new TestRoot
+ {
+ Width = 400,
+ Height = 200,
+ Child = border = new Border
+ {
+ HorizontalAlignment = HorizontalAlignment.Left,
+ Background = Brushes.Red,
+ Width = 100,
+ RenderTransform = new ScaleTransform(0.5, 1),
+ FlowDirection = FlowDirection.RightToLeft
+ }
+ };
+
+ tree.Measure(Size.Infinity);
+ tree.Arrange(new Rect(tree.DesiredSize));
+
+ var scene = new Scene(tree);
+ var sceneBuilder = new SceneBuilder();
+ sceneBuilder.UpdateAll(scene);
+
+ var expectedTransform = new Matrix(-1, 0, 0, 1, 100, 0) * Matrix.CreateScale(0.5, 1) * Matrix.CreateTranslation(25, 0);
+ var borderNode = scene.FindNode(border);
+ Assert.Equal(expectedTransform, borderNode.Transform);
+ }
+ }
+
[Fact]
public void Should_Update_Border_Background_Node()
{
diff --git a/tests/Avalonia.Controls.UnitTests/ComboBoxTests.cs b/tests/Avalonia.Controls.UnitTests/ComboBoxTests.cs
index 98695fe88e..aa32af7e51 100644
--- a/tests/Avalonia.Controls.UnitTests/ComboBoxTests.cs
+++ b/tests/Avalonia.Controls.UnitTests/ComboBoxTests.cs
@@ -8,7 +8,7 @@ using Avalonia.Data;
using Avalonia.Input;
using Avalonia.LogicalTree;
using Avalonia.Media;
-using Avalonia.Threading;
+using Avalonia.VisualTree;
using Avalonia.UnitTests;
using Xunit;
@@ -336,5 +336,104 @@ namespace Avalonia.Controls.UnitTests
Assert.Equal(1, count);
}
}
+
+ [Fact]
+ public void FlowDirection_Of_RectangleContent_Shuold_Be_LeftToRight()
+ {
+ var items = new[]
+ {
+ new ComboBoxItem()
+ {
+ Content = new Control()
+ }
+ };
+ var target = new ComboBox
+ {
+ FlowDirection = FlowDirection.RightToLeft,
+ Items = items,
+ Template = GetTemplate()
+ };
+
+ var root = new TestRoot(target);
+ target.ApplyTemplate();
+ target.SelectedIndex = 0;
+
+ var rectangle = target.GetValue(ComboBox.SelectionBoxItemProperty) as Rectangle;
+
+ Assert.Equal(FlowDirection.LeftToRight, rectangle.FlowDirection);
+ }
+
+ [Fact]
+ public void FlowDirection_Of_RectangleContent_Updated_After_InvalidateMirrorTransform()
+ {
+ var parentContent = new Decorator()
+ {
+ Child = new Control()
+ };
+ var items = new[]
+ {
+ new ComboBoxItem()
+ {
+ Content = parentContent.Child
+ }
+ };
+ var target = new ComboBox
+ {
+ Items = items,
+ Template = GetTemplate()
+ };
+
+ var root = new TestRoot(target);
+ target.ApplyTemplate();
+ target.SelectedIndex = 0;
+
+ var rectangle = target.GetValue(ComboBox.SelectionBoxItemProperty) as Rectangle;
+ Assert.Equal(FlowDirection.LeftToRight, rectangle.FlowDirection);
+
+ parentContent.FlowDirection = FlowDirection.RightToLeft;
+ target.FlowDirection = FlowDirection.RightToLeft;
+
+ Assert.Equal(FlowDirection.RightToLeft, rectangle.FlowDirection);
+ }
+
+ [Fact]
+ public void FlowDirection_Of_RectangleContent_Updated_After_OpenPopup()
+ {
+ using (UnitTestApplication.Start(TestServices.StyledWindow))
+ {
+ var parentContent = new Decorator()
+ {
+ Child = new Control()
+ };
+ var items = new[]
+ {
+ new ComboBoxItem()
+ {
+ Content = parentContent.Child
+ }
+ };
+ var target = new ComboBox
+ {
+ FlowDirection = FlowDirection.RightToLeft,
+ Items = items,
+ Template = GetTemplate()
+ };
+
+ var root = new TestRoot(target);
+ target.ApplyTemplate();
+ target.SelectedIndex = 0;
+
+ var rectangle = target.GetValue(ComboBox.SelectionBoxItemProperty) as Rectangle;
+ Assert.Equal(FlowDirection.LeftToRight, rectangle.FlowDirection);
+
+ parentContent.FlowDirection = FlowDirection.RightToLeft;
+
+ var popup = target.GetVisualDescendants().OfType().First();
+ popup.PlacementTarget = new Window();
+ popup.Open();
+
+ Assert.Equal(FlowDirection.RightToLeft, rectangle.FlowDirection);
+ }
+ }
}
}
diff --git a/tests/Avalonia.Controls.UnitTests/FlowDirectionTests.cs b/tests/Avalonia.Controls.UnitTests/FlowDirectionTests.cs
new file mode 100644
index 0000000000..6c43103ecb
--- /dev/null
+++ b/tests/Avalonia.Controls.UnitTests/FlowDirectionTests.cs
@@ -0,0 +1,57 @@
+using Avalonia.Media;
+using Xunit;
+
+namespace Avalonia.Controls.UnitTests
+{
+ public class FlowDirectionTests
+ {
+ [Fact]
+ public void HasMirrorTransform_Should_Be_True()
+ {
+ var target = new Control
+ {
+ FlowDirection = FlowDirection.RightToLeft,
+ };
+
+ Assert.True(target.HasMirrorTransform);
+ }
+
+ [Fact]
+ public void HasMirrorTransform_Of_LTR_Children_Should_Be_True_For_RTL_Parent()
+ {
+ Control child;
+ var target = new Decorator
+ {
+ FlowDirection = FlowDirection.RightToLeft,
+ Child = child = new Control()
+ };
+
+ child.FlowDirection = FlowDirection.LeftToRight;
+
+ Assert.True(target.HasMirrorTransform);
+ Assert.True(child.HasMirrorTransform);
+ }
+
+ [Fact]
+ public void HasMirrorTransform_Of_Children_Is_Updated_After_Parent_Changeed()
+ {
+ Control child;
+ var target = new Decorator
+ {
+ FlowDirection = FlowDirection.LeftToRight,
+ Child = child = new Control()
+ {
+ FlowDirection = FlowDirection.LeftToRight,
+ }
+ };
+
+ Assert.False(target.HasMirrorTransform);
+ Assert.False(child.HasMirrorTransform);
+
+ target.FlowDirection = FlowDirection.RightToLeft;
+
+ Assert.True(target.HasMirrorTransform);
+ Assert.True(child.HasMirrorTransform);
+ }
+ }
+}