-
Notifications
You must be signed in to change notification settings - Fork 2k
[Windows] Fix Shell title bar overlap with window controls in RTL mode #33109
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
62a5825
628ac3d
f5bd4e8
5fa226c
9ff6a4b
8daac59
c5c00f1
efdad8c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,5 +1,7 @@ | ||
| #nullable disable | ||
| using System; | ||
| using System.Runtime.InteropServices; | ||
| using Microsoft.Extensions.DependencyInjection; | ||
| using Microsoft.Maui.Controls.Platform; | ||
| using Microsoft.UI.Xaml; | ||
| using Microsoft.UI.Xaml.Controls; | ||
|
|
@@ -12,6 +14,14 @@ namespace Microsoft.Maui.Controls.Handlers | |
| { | ||
| public partial class ShellHandler : ViewHandler<Shell, ShellView> | ||
| { | ||
| [DllImport("user32.dll", SetLastError = true)] | ||
| static extern int GetWindowLong(IntPtr hWnd, int nIndex); | ||
|
|
||
| [DllImport("user32.dll", SetLastError = true)] | ||
| static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong); | ||
|
|
||
| const int GWL_EXSTYLE = -20; | ||
| const int WS_EX_LAYOUTRTL = 0x00400000; | ||
| ScrollViewer _scrollViewer; | ||
| double? _topAreaHeight = null; | ||
| double? _headerHeight = null; | ||
|
|
@@ -164,6 +174,23 @@ public static void MapFlyout(ShellHandler handler, IFlyoutView flyoutView) | |
| internal static void MapFlowDirection(ShellHandler handler, Shell view) | ||
| { | ||
| handler.PlatformView.UpdateFlowDirection(view); | ||
| var windowRootView = handler.MauiContext?.GetNavigationRootManager()?.RootView as WindowRootView; | ||
| var window = handler.MauiContext?.Services?.GetService<Microsoft.UI.Xaml.Window>(); | ||
|
|
||
| if (window == null) | ||
| return; | ||
|
|
||
| var hwnd = WinRT.Interop.WindowNative.GetWindowHandle(window); | ||
| var isRtl = view.FlowDirection == FlowDirection.RightToLeft; | ||
| var exStyle = GetWindowLong(hwnd, GWL_EXSTYLE); | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [major] Logic and Correctness — This derives the native window RTL state from |
||
|
|
||
| // Apply or remove WS_EX_LAYOUTRTL to mirror the window including title bar buttons | ||
| var newExStyle = isRtl ? (exStyle | WS_EX_LAYOUTRTL) : (exStyle & ~WS_EX_LAYOUTRTL); | ||
| if (exStyle != newExStyle) | ||
| SetWindowLong(hwnd, GWL_EXSTYLE, newExStyle); | ||
|
Shalini-Ashokan marked this conversation as resolved.
|
||
|
|
||
| if (windowRootView != null) | ||
| windowRootView.FlowDirection = isRtl ? Microsoft.UI.Xaml.FlowDirection.RightToLeft : Microsoft.UI.Xaml.FlowDirection.LeftToRight; | ||
| } | ||
|
|
||
| public static void MapIsPresented(ShellHandler handler, IFlyoutView flyoutView) | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,59 @@ | ||
| namespace Maui.Controls.Sample.Issues; | ||
|
|
||
| [Issue(IssueTracker.Github, 32476, "Binding RTL FlowDirection in Shell causes Flyout MenuIcon and native window controls to overlap", PlatformAffected.UWP)] | ||
| public class Issue32476 : Shell | ||
| { | ||
| public Issue32476() | ||
| { | ||
| FlyoutBehavior = FlyoutBehavior.Flyout; | ||
| var button = new Button | ||
| { | ||
| Text = "Toggle FlowDirection to RTL", | ||
| AutomationId = "ToggleButton" | ||
| }; | ||
|
|
||
| var buttonTapLabel = new Label | ||
| { | ||
| Text = "Tap the button to toggle FlowDirection to RTL", | ||
| HorizontalOptions = LayoutOptions.Center | ||
| }; | ||
|
|
||
| button.Clicked += (s, e) => | ||
| { | ||
| buttonTapLabel.Text = "Toggling FlowDirection..."; | ||
| FlowDirection = FlowDirection.RightToLeft; | ||
| buttonTapLabel.Text = "FlowDirection is now RTL"; | ||
| }; | ||
|
|
||
| var contentPage = new ContentPage | ||
| { | ||
| Content = new VerticalStackLayout | ||
| { | ||
| Padding = 20, | ||
| Spacing = 10, | ||
| Children = | ||
| { | ||
| new Label | ||
| { | ||
| Text = "Tap the button to toggle FlowDirection to RTL. The Flyout MenuIcon must not overlap with native window controls.", | ||
| LineBreakMode = LineBreakMode.WordWrap | ||
| }, | ||
| button, | ||
| buttonTapLabel | ||
| } | ||
| } | ||
| }; | ||
| Items.Add(new FlyoutItem | ||
| { | ||
| Title = "Home", | ||
| Items = | ||
| { | ||
| new ShellContent | ||
| { | ||
| Title = "Main", | ||
| Content = contentPage | ||
| } | ||
| } | ||
| }); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,26 @@ | ||
| #if MACCATALYST || WINDOWS // Native window controls (minimize, maximize, close) are applicable only on Windows and MacCatalyst | ||
| using NUnit.Framework; | ||
| using UITest.Appium; | ||
| using UITest.Core; | ||
| namespace Microsoft.Maui.TestCases.Tests.Issues; | ||
|
|
||
| public class Issue32476 : _IssuesUITest | ||
| { | ||
| public Issue32476(TestDevice testDevice) : base(testDevice) | ||
| { | ||
| } | ||
| public override string Issue => "Binding RTL FlowDirection in Shell causes Flyout MenuIcon and native window controls to overlap"; | ||
| [Test] | ||
| [Category(UITestCategories.Shell)] | ||
| public void ShellRTLFlowDirectionShouldNotCauseOverlap() | ||
| { | ||
| App.WaitForElement("ToggleButton"); | ||
| App.Tap("ToggleButton"); | ||
| App.Tap("ToggleButton"); | ||
|
|
||
| // wait for window layout to update after flow direction change. | ||
| Task.Delay(500).Wait(); | ||
| VerifyScreenshot(includeTitleBar: true); | ||
| } | ||
| } | ||
| #endif |
Uh oh!
There was an error while loading. Please reload this page.