diff --git a/build/PackageDiffIgnore.xml b/build/PackageDiffIgnore.xml index 64cc3c27acdb..16527fa19d91 100644 --- a/build/PackageDiffIgnore.xml +++ b/build/PackageDiffIgnore.xml @@ -7267,6 +7267,12 @@ + + AllQuery(q).Marked("UnitTestsRootControl")); async Task IsTestExecutionDone() + { + return await GetWithRetry("IsTestExecutionDone", () => runningState.GetDependencyPropertyValue("Text")?.ToString().Equals("Finished", StringComparison.OrdinalIgnoreCase) ?? false); + } + + async Task GetWithRetry(string logName, Func getter, int timeoutSeconds = 10) { var sw = Stopwatch.StartNew(); Exception lastException = null; @@ -49,19 +54,19 @@ async Task IsTestExecutionDone() { try { - return runningState.GetDependencyPropertyValue("Text")?.ToString().Equals("Finished", StringComparison.OrdinalIgnoreCase) ?? false; + return getter(); } catch (Exception e) { lastException = e; - Console.WriteLine($"IsTestExecutionDone failed with {e.Message}"); + Console.WriteLine($"{logName} failed with {e.Message}"); } await Task.Delay(TimeSpan.FromSeconds(.5)); - Console.WriteLine($"IsTestExecutionDone retrying"); + Console.WriteLine($"{logName} retrying"); } - while (sw.Elapsed < TimeSpan.FromSeconds(10)); + while (sw.Elapsed < TimeSpan.FromSeconds(timeoutSeconds)); throw lastException; } @@ -75,7 +80,8 @@ async Task IsTestExecutionDone() while(DateTimeOffset.Now - lastChange < TestRunTimeout) { - var newValue = GetValue(nameof(runTestCount), runTestCount); + var newValue = await GetWithRetry("GetRunTestCount", () => runTestCount.GetDependencyPropertyValue("Text")?.ToString()); + if (lastValue != newValue) { lastChange = DateTimeOffset.Now; diff --git a/src/SamplesApp/UITests.Shared/Microsoft_UI_Xaml_Controls/CommandBarTests/CommandBar_Primary_And_Secondary.xaml b/src/SamplesApp/UITests.Shared/Microsoft_UI_Xaml_Controls/CommandBarTests/CommandBar_Primary_And_Secondary.xaml new file mode 100644 index 000000000000..4c83794ac09c --- /dev/null +++ b/src/SamplesApp/UITests.Shared/Microsoft_UI_Xaml_Controls/CommandBarTests/CommandBar_Primary_And_Secondary.xaml @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + diff --git a/src/SamplesApp/UITests.Shared/Microsoft_UI_Xaml_Controls/CommandBarTests/CommandBar_Primary_And_Secondary.xaml.cs b/src/SamplesApp/UITests.Shared/Microsoft_UI_Xaml_Controls/CommandBarTests/CommandBar_Primary_And_Secondary.xaml.cs new file mode 100644 index 000000000000..72e61ed965e3 --- /dev/null +++ b/src/SamplesApp/UITests.Shared/Microsoft_UI_Xaml_Controls/CommandBarTests/CommandBar_Primary_And_Secondary.xaml.cs @@ -0,0 +1,29 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Runtime.InteropServices.WindowsRuntime; +using Uno.UI.Samples.Controls; +using Windows.Foundation; +using Windows.Foundation.Collections; +using Windows.UI.Xaml; +using Windows.UI.Xaml.Controls; +using Windows.UI.Xaml.Controls.Primitives; +using Windows.UI.Xaml.Data; +using Windows.UI.Xaml.Input; +using Windows.UI.Xaml.Media; +using Windows.UI.Xaml.Navigation; + +// The Blank Page item template is documented at https://go.microsoft.com/fwlink/?LinkId=234238 + +namespace UITests.Microsoft_UI_Xaml_Controls.CommandBarTests +{ + [Sample("CommandBar")] + public sealed partial class CommandBar_Primary_And_Secondary : Page + { + public CommandBar_Primary_And_Secondary() + { + this.InitializeComponent(); + } + } +} diff --git a/src/SamplesApp/UITests.Shared/UITests.Shared.projitems b/src/SamplesApp/UITests.Shared/UITests.Shared.projitems index 78dfcca71d5f..c1f4c324e595 100644 --- a/src/SamplesApp/UITests.Shared/UITests.Shared.projitems +++ b/src/SamplesApp/UITests.Shared/UITests.Shared.projitems @@ -37,6 +37,10 @@ Designer MSBuild:Compile + + Designer + MSBuild:Compile + Designer MSBuild:Compile @@ -4368,6 +4372,9 @@ WinUIColorPickerPage.xaml + + CommandBar_Primary_And_Secondary.xaml + ImageIconPage.xaml diff --git a/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/Button/AppBar_KeyBoard.xaml b/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/Button/AppBar_KeyBoard.xaml index 21d356d1a57d..65f93d40f046 100644 --- a/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/Button/AppBar_KeyBoard.xaml +++ b/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/Button/AppBar_KeyBoard.xaml @@ -14,17 +14,20 @@ diff --git a/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/CommandBar/BackGesture/BackGesture_CollapsedNavigationCommand.xaml b/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/CommandBar/BackGesture/BackGesture_CollapsedNavigationCommand.xaml index 9bdb6bddaa81..53fcd1c7e0f8 100644 --- a/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/CommandBar/BackGesture/BackGesture_CollapsedNavigationCommand.xaml +++ b/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/CommandBar/BackGesture/BackGesture_CollapsedNavigationCommand.xaml @@ -39,4 +39,4 @@ Grid.Row="2" /> - \ No newline at end of file + diff --git a/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/CommandBar/CommandBar_Extensions.xaml b/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/CommandBar/CommandBar_Extensions.xaml index 7c270a5170d1..e941b2333b74 100644 --- a/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/CommandBar/CommandBar_Extensions.xaml +++ b/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/CommandBar/CommandBar_Extensions.xaml @@ -25,51 +25,60 @@ - + + + - - - - - - - - - + + + + + + + + + + + - - - - - - - - - + + + + + + + + + + + - - - + + + + + + + + + + + - + - - - - - - - - + + + diff --git a/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/CommandBar/CommandBar_Native_With_AppBarButton_With_Foreground.xaml b/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/CommandBar/CommandBar_Native_With_AppBarButton_With_Foreground.xaml index 168a97ca15a0..5cb93fc09990 100644 --- a/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/CommandBar/CommandBar_Native_With_AppBarButton_With_Foreground.xaml +++ b/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/CommandBar/CommandBar_Native_With_AppBarButton_With_Foreground.xaml @@ -1,47 +1,54 @@ - + - - - - - - - - - - - - - - - - - - - - + + + - \ No newline at end of file + + + - - - - - - - - - - - - - - - - - - - 0,4,0,4 - + + - @@ -373,10 +374,11 @@ + @@ -19,15 +20,15 @@ 1 0.5 - - diff --git a/src/Uno.UI.FluentTheme.v2/Resources/Version2/PriorityDefault/CommandBar_themeresources.xaml b/src/Uno.UI.FluentTheme.v2/Resources/Version2/PriorityDefault/CommandBar_themeresources.xaml index 3f83f89fe24d..d8cf3fe3b8fe 100644 --- a/src/Uno.UI.FluentTheme.v2/Resources/Version2/PriorityDefault/CommandBar_themeresources.xaml +++ b/src/Uno.UI.FluentTheme.v2/Resources/Version2/PriorityDefault/CommandBar_themeresources.xaml @@ -7,10 +7,12 @@ xmlns:contract8Present="http://schemas.microsoft.com/winfx/2006/xaml/presentation?IsApiContractPresent(Windows.Foundation.UniversalApiContract,8)" xmlns:contract12Present="http://schemas.microsoft.com/winfx/2006/xaml/presentation?IsApiContractPresent(Windows.Foundation.UniversalApiContract,12)" xmlns:contract12NotPresent="http://schemas.microsoft.com/winfx/2006/xaml/presentation?IsApiContractNotPresent(Windows.Foundation.UniversalApiContract,12)" - xmlns:local="using:Microsoft.UI.Xaml.Controls" + xmlns:local="using:Windows.UI.Xaml.Controls" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> + 64 + 48 160 240 480 @@ -36,6 +38,8 @@ 0 + 64 + 48 @@ -60,6 +64,8 @@ 0 + 64 + 48 160 240 480 @@ -86,16 +92,15 @@ - 64 - 48 + 2,6,6,6 6 - + 0,4,0,4 - - - + + + + - 14,19,14,0 16 - 64 - 48 + 14,19,14,0 - @@ -9924,7 +9928,8 @@ - + + @@ -9942,14 +9947,14 @@ 1 1 0.5 - - @@ -14342,8 +14347,7 @@ 2,6,6,6 6 0,4,0,4 - - - + + + + + + + + + + + "); + + cmdBar.Template = cmdBarTemplate; + cmdBar.ApplyTemplate(); + }); + await WindowHelper.WaitForIdle(); + } + + [TestMethod] + + [Description("Validates that CommandBar opens and closes, with appropriate events firing, using IsOpen property.")] + public async Task CanOpenAndCloseUsingAPI() + { + TestCleanupWrapper cleanup; + + Func openFunc = async (cmdBar) => await RunOnUIThread(() => cmdBar.IsOpen = true); + Func closeFunc = async (cmdBar) => await RunOnUIThread(() => cmdBar.IsOpen = false); + + await ValidateOpenAndCloseWorker(openFunc, closeFunc); + } + + [TestMethod] + + [Description("Validates that CommandBar opens and closes, with appropriate events firing, using taps on More Button.")] + [TestProperty("TestPass:ExcludeOn", "WindowsCore")] + public async Task CanOpenAndCloseUsingMoreButton() + { + TestCleanupWrapper cleanup; + + Func openAndCloseFunc = async (cmdBar) => + { + var moreButton = await GetMoreButton(cmdBar); + TestServices.InputHelper.Tap(moreButton); + }; + + await ValidateOpenAndCloseWorker(openAndCloseFunc, openAndCloseFunc); + } + + [TestMethod] + + [Description("Validates that CommandBar closes when the device's Back button is pressed.")] + [TestProperty("Hosting:Mode", "UAP")] + [Ignore("InjectBackButtonPress not implemented.")] + public async Task CanCloseUsingBackButton() + { + TestCleanupWrapper cleanup; + + Func openFunc = async (cmdBar) => await RunOnUIThread(() => cmdBar.IsOpen = true); + Func closeFunc = async (cmdBar) => + { + bool backButtonPressHandled = false; + TestServices.Utilities.InjectBackButtonPress(ref backButtonPressHandled); + VERIFY_IS_TRUE(backButtonPressHandled); + }; + + await ValidateOpenAndCloseWorker(openFunc, closeFunc); + } + + [TestMethod] + + [Description("Validates that CommandBar can close when a primary command is selected from the overflow.")] + public async Task DoesCloseOnPrimaryCommandSelection() + { + TestCleanupWrapper cleanup; + + Func openFunc = async (cmdBar) => await RunOnUIThread(() => cmdBar.IsOpen = true); + Func closeFunc = async (cmdBar) => + { + FrameworkElement tapTarget = null; + + await RunOnUIThread(() => tapTarget = (FrameworkElement)cmdBar.PrimaryCommands[0]); + + TestServices.InputHelper.Tap(tapTarget); + }; + + await ValidateOpenAndCloseWorker(openFunc, closeFunc); + } + + [TestMethod] + + [Description("Validates that CommandBar can close when a secondary command is selected from the overflow.")] + [TestProperty("TestPass:IncludeOnlyOn", "Desktop")] + public async Task DoesCloseOnSecondaryCommandSelection() + { + TestCleanupWrapper cleanup; + + Func openFunc = async (cmdBar) => await RunOnUIThread(() => cmdBar.IsOpen = true); + Func closeFunc = async (cmdBar) => + { + FrameworkElement tapTarget = null; + + await RunOnUIThread(() => tapTarget = (FrameworkElement)cmdBar.SecondaryCommands[0]); + + TestServices.InputHelper.Tap(tapTarget); + }; + + await ValidateOpenAndCloseWorker(openFunc, closeFunc); + } + + [TestMethod] + + [Description("Validates that items can be added to the CommandBar's collection properties.")] + + public async Task CanAddToAndRemoveFromCommandCollections() + { + TestCleanupWrapper cleanup; + + // Make sure we can add/remove items to/from our command collections. + await RunOnUIThread(() => + { + CommandBar cmdBar = new CommandBar(); + + VERIFY_IS_TRUE(cmdBar.PrimaryCommands.Count == 0); + VERIFY_IS_TRUE(cmdBar.SecondaryCommands.Count == 0); + + var btn1 = new AppBarButton(); + cmdBar.PrimaryCommands.Append(btn1); + VERIFY_IS_TRUE(btn1 == (AppBarButton)cmdBar.PrimaryCommands[0]); + + var btn2 = new AppBarToggleButton(); + cmdBar.PrimaryCommands.Append(btn2); + VERIFY_IS_TRUE(btn2 == cmdBar.PrimaryCommands[1]); + + cmdBar.PrimaryCommands.RemoveAt(1); + VERIFY_IS_TRUE(cmdBar.PrimaryCommands.Count == 1); + + cmdBar.PrimaryCommands.RemoveAt(0); + VERIFY_IS_TRUE(cmdBar.PrimaryCommands.Count == 0); + + var btn3 = new AppBarButton(); + cmdBar.SecondaryCommands.Append(btn3); + VERIFY_IS_TRUE(btn3 == cmdBar.SecondaryCommands[0]); + + var btn4 = new AppBarToggleButton(); + cmdBar.SecondaryCommands.Append(btn4); + VERIFY_IS_TRUE(btn4 == cmdBar.SecondaryCommands[1]); + + cmdBar.SecondaryCommands.RemoveAt(1); + VERIFY_IS_TRUE(cmdBar.SecondaryCommands.Count == 1); + + cmdBar.SecondaryCommands.RemoveAt(0); + VERIFY_IS_TRUE(cmdBar.SecondaryCommands.Count == 0); + + cmdBar.SecondaryCommands.Append(btn3); + VERIFY_IS_TRUE(btn3 == cmdBar.SecondaryCommands.GetAt(0)); + + cmdBar.SecondaryCommands.SetAt(0, btn4); + VERIFY_IS_TRUE(btn4 == cmdBar.SecondaryCommands.GetAt(0)); + + cmdBar.SecondaryCommands.RemoveAt(cmdBar.SecondaryCommands.Count - 1); + VERIFY_IS_TRUE(cmdBar.SecondaryCommands.Count == 0); + + cmdBar.PrimaryCommands.Append(btn1); + VERIFY_IS_TRUE(btn1 == cmdBar.PrimaryCommands.GetAt(0)); + + cmdBar.PrimaryCommands.Append(btn2); + VERIFY_IS_TRUE(btn2 == cmdBar.PrimaryCommands.GetAt(1)); + + cmdBar.SecondaryCommands.Append(btn3); + VERIFY_IS_TRUE(btn3 == cmdBar.SecondaryCommands.GetAt(0)); + + cmdBar.SecondaryCommands.Append(btn4); + VERIFY_IS_TRUE(btn4 == cmdBar.SecondaryCommands.GetAt(1)); + + cmdBar.PrimaryCommands.Clear(); + VERIFY_IS_TRUE(cmdBar.PrimaryCommands.Count == 0); + + cmdBar.SecondaryCommands.Clear(); + VERIFY_IS_TRUE(cmdBar.SecondaryCommands.Count == 0); + }); + + // Make sure we can add items to our command collections via the parser. + await RunOnUIThread(() => + { + CommandBar cmdBar = (CommandBar)XamlReader.Load(@" + + + + + + + + + "); + + VERIFY_IS_NOT_NULL(cmdBar); + VERIFY_IS_TRUE(cmdBar.PrimaryCommands.Count == 2); + VERIFY_IS_TRUE(cmdBar.SecondaryCommands.Count == 2); + + var btn1 = cmdBar.PrimaryCommands.GetAt(0) as AppBarToggleButton; + VERIFY_IS_NOT_NULL(btn1); + VERIFY_IS_TRUE(btn1.Label == "btn1"); + + var btn2 = cmdBar.PrimaryCommands.GetAt(1) as AppBarButton; + VERIFY_IS_NOT_NULL(btn2); + VERIFY_IS_TRUE(btn2.Label == "btn2"); + + var btn3 = cmdBar.SecondaryCommands.GetAt(0) as AppBarToggleButton; + VERIFY_IS_NOT_NULL(btn3); + VERIFY_IS_TRUE(btn3.Label == "btn3"); + + var btn4 = cmdBar.SecondaryCommands.GetAt(1) as AppBarButton; + VERIFY_IS_NOT_NULL(btn4); + VERIFY_IS_TRUE(btn4.Label == "btn4"); + }); + } + + [TestMethod] + + [Description("Validates that the overflow's open direction and alignment.")] + + public async Task ValidateOverflowPlacement() + { + TestCleanupWrapper cleanup; + + LOG_OUTPUT("ValidateOverflowPosition: Opened Up, Aligned Right, FlowDirection=LTR"); + await ValidateOverflowPlacementWorker(OverflowOpenDirection.Up, OverflowAlignment.Right, false /*isRTL*/); + + LOG_OUTPUT("ValidateOverflowPosition: Opened Up, Aligned Left, FlowDirection=LTR"); + await ValidateOverflowPlacementWorker(OverflowOpenDirection.Up, OverflowAlignment.Left, false /*isRTL*/); + + LOG_OUTPUT("ValidateOverflowPosition: Opened Down, Aligned Right, FlowDirection=LTR"); + await ValidateOverflowPlacementWorker(OverflowOpenDirection.Down, OverflowAlignment.Right, false /*isRTL*/); + + LOG_OUTPUT("ValidateOverflowPosition: Opened Down, Aligned Left, FlowDirection=LTR"); + await ValidateOverflowPlacementWorker(OverflowOpenDirection.Down, OverflowAlignment.Left, false /*isRTL*/); + + // Validate the same scenarios, except with FlowDirection=RTL + LOG_OUTPUT("ValidateOverflowPosition: Opened Up, Aligned Right, FlowDirection=RT"); + await ValidateOverflowPlacementWorker(OverflowOpenDirection.Up, OverflowAlignment.Right, true /*isRTL*/); + + LOG_OUTPUT("ValidateOverflowPosition: Opened Up, Aligned Left, FlowDirection=RT"); + await ValidateOverflowPlacementWorker(OverflowOpenDirection.Up, OverflowAlignment.Left, true /*isRTL*/); + + LOG_OUTPUT("ValidateOverflowPosition: Opened Down, Aligned Right, FlowDirection=RT"); + await ValidateOverflowPlacementWorker(OverflowOpenDirection.Down, OverflowAlignment.Right, true /*isRTL*/); + + LOG_OUTPUT("ValidateOverflowPosition: Opened Down, Aligned Left, FlowDirection=RT"); + await ValidateOverflowPlacementWorker(OverflowOpenDirection.Down, OverflowAlignment.Left, true /*isRTL*/); + } + + [TestMethod] + + [Description("Validates that the overflow snaps to the window width when it's less than 480.")] + [Ignore("SetWindowSizeOverride not implemented.")] + public async Task ValidateOverflowSnapsToWindowWidth() + { + TestCleanupWrapper cleanup; + + var loadedEvent = new Event(); + var loadedRegistration = CreateSafeEventRegistration("Loaded"); + + double expectedWidth = 400; + + // Override the window size to be < 480 to simulate the conditions + // under which the overflow menu will snap. + WindowHelper.SetWindowSizeOverride(new Size(expectedWidth, 600)); + + CommandBar cmdBar = null; + + await RunOnUIThread(() => + { + cmdBar = new CommandBar(); + cmdBar.IsOpen = true; + + var button = new AppBarButton(); + button.Label = "menu item"; + + cmdBar.SecondaryCommands.Append(button); + + loadedRegistration.Attach(cmdBar, (s, e) => + { + LOG_OUTPUT("CommandBar.Loaded raised."); + loadedEvent.Set(); + }); + + SetWindowContent(cmdBar); + }); + + await loadedEvent.WaitForDefault(); + await WindowHelper.WaitForIdle(); + + await RunOnUIThread(() => + { + var overflowContentRoot = TreeHelper.GetVisualChildByNameFromOpenPopups("OverflowContentRoot", cmdBar); + VERIFY_IS_NOT_NULL(overflowContentRoot); + + VERIFY_ARE_EQUAL(overflowContentRoot.MinWidth, expectedWidth); + VERIFY_ARE_EQUAL(overflowContentRoot.ActualWidth, expectedWidth); + }); + } + + [TestMethod] + + [Description("Validates that the overflow's max height is 50% of the window height.")] + [TestProperty("Hosting:Mode", "UAP")] + [Ignore("SetWindowSizeOverride not implemented")] + public async Task ValidateOverflowMaxHeight() + { + // TestCleanupWrapper cleanup; + + // const double overflowHeight = 300; + // // 40 for WindowedPopupPadding + // double expectedHeight = overflowHeight + 40; + // TestServices::WindowHelper->SetWindowSizeOverride(wf::Size(500, static_cast(overflowHeight * 2))); + + // // We add a rectangle to give us extra space in which to do translate transforms + // // when using windowed popups, so we add that to the max height and need to account for it. + // if (PopupHelper::AreWindowedPopupsEnabled()) + // { + // expectedHeight += 64; + // } + + // auto loadedEvent = std::make_shared(); + // auto loadedRegistration = CreateSafeEventRegistration(xaml_controls::CommandBar, Loaded); + + // xaml_controls::CommandBar ^ cmdBar = nullptr; + + // RunOnUIThread([&]() + + //{ + // cmdBar = ref new xaml_controls::CommandBar(); + // cmdBar->IsOpen = true; + + // for (size_t i = 0; i < 50; ++i) + // { + // auto button = ref new xaml_controls::AppBarButton(); + // button->Label = "menu item"; + + // cmdBar->SecondaryCommands->Append(button); + // } + + // loadedRegistration.Attach(cmdBar, [&]() + + // { + // LOG_OUTPUT("CommandBar.Loaded raised."); + // loadedEvent->Set(); + // }); + + // TestServices::WindowHelper->WindowContent = cmdBar; + // }); + + // loadedEvent->WaitForDefault(); + // TestServices::WindowHelper->WaitForIdle(); + + // RunOnUIThread([&]() + + //{ + // auto overflowContentRoot = safe_cast < xaml::FrameworkElement ^> (TreeHelper::GetVisualChildByNameFromOpenPopups("OverflowContentRoot", cmdBar)); + // VERIFY_IS_NOT_NULL(overflowContentRoot); + + // VERIFY_ARE_EQUAL(overflowContentRoot->MaxHeight, expectedHeight); + // VERIFY_ARE_EQUAL(overflowContentRoot->ActualHeight, expectedHeight); + // }); + } + + [TestMethod] + + [Description("Validates that resizing the AppBar after opening and closing causes its width to properly get updated.")] + [TestProperty("Hosting:Mode", "UAP")] + public async Task CanResizeCommandBarAfterOpeningAndClosing() + { + TestCleanupWrapper cleanup; + + Page page = null; + CommandBar cmdBar = null; + Button moreButton = null; + var originalMoreButtonOffset = new Point(); + + await RunOnUIThread(() => + { + cmdBar = (CommandBar)XamlReader.Load(@" + + + + + + + + + + + + + "); + + var page = WindowHelper.SetupSimulatedAppPage(); + + //Uno TODO: Use Page.BottomAppBar instead of Page.Content + SetPageContent(cmdBar, page); + }); + await WindowHelper.WaitForIdle(); + + await RunOnUIThread(() => + { + moreButton = (Button)TreeHelper.GetVisualChildByName(cmdBar, "MoreButton"); + cmdBar.IsOpen = true; + }); + await WindowHelper.WaitForIdle(); + + await RunOnUIThread(() => + { + originalMoreButtonOffset = moreButton.TransformToVisual(null).TransformPoint(new Point(0, 0)); + cmdBar.IsOpen = false; + }); + await WindowHelper.WaitForIdle(); + + await RunOnUIThread(() => + { + cmdBar.Margin = ThicknessHelper.FromLengths(0, 0, 0, 0); + cmdBar.IsOpen = true; + }); + await WindowHelper.WaitForIdle(); + + await RunOnUIThread(() => + { + var newMoreButtonPosition = moreButton.TransformToVisual(null).TransformPoint(new Point(0, 0)); + VERIFY_IS_GREATER_THAN(newMoreButtonPosition.X, originalMoreButtonOffset.X); + + cmdBar.IsOpen = false; + }); + } + + [TestMethod] + + [Description("Validates that a CommandBar can use an AppBarButton taller than the app window.")] + [TestProperty("TestPass:IncludeOnlyOn", "Desktop")] + [TestProperty("Hosting:Mode", "UAP")] + [Ignore("Missing implementations: BottomAppBar, SetWindowSizeOverride, KeyboardHelper, InputHelper")] + public async Task CanUseLargeAppBarButton() + { + TestCleanupWrapper cleanup; + WindowHelper.SetWindowSizeOverride(new Size(400, 400)); + + Page page = null; + CommandBar cmdBar = null; + AppBarButton appBarButton = null; + + await RunOnUIThread(() => + { + cmdBar = (CommandBar)XamlReader.Load(@" + + + + + + MenuFlyoutItem + + + + + + "); + VERIFY_IS_NOT_NULL(cmdBar); + + appBarButton = (AppBarButton)cmdBar.SecondaryCommands[0]; + VERIFY_IS_NOT_NULL(appBarButton); + + var page = WindowHelper.SetupSimulatedAppPage(); + VERIFY_IS_NOT_NULL(page); + + //TODO: BottomAppBar not implemented + //page.BottomAppBar = cmdBar; + }); + await WindowHelper.WaitForIdle(); + + LOG_OUTPUT("Tabbing into the BottomAppBar's SecondaryCommands."); + KeyboardHelper.Tab(); + await WindowHelper.WaitForIdle(); + + LOG_OUTPUT("Opening the BottomAppBar's SecondaryCommands."); + KeyboardHelper.Enter(); + await WindowHelper.WaitForIdle(); + + LOG_OUTPUT("Tabbing into the tall AppBarButton."); + KeyboardHelper.Tab(); + await WindowHelper.WaitForIdle(); + + LOG_OUTPUT("Scrolling down within the AppBarButton."); + KeyboardHelper.PageDown(); + await WindowHelper.WaitForIdle(); + + LOG_OUTPUT("Moving mouse over the AppBarButton."); + TestServices.InputHelper.MoveMouse(appBarButton); + await WindowHelper.WaitForIdle(); + + LOG_OUTPUT("Holding the AppBarButton."); + TestServices.InputHelper.Hold(appBarButton); + await WindowHelper.WaitForIdle(); + + await RunOnUIThread(() => + { + LOG_OUTPUT("Closing the BottomAppBar."); + cmdBar.IsOpen = false; + }); + await WindowHelper.WaitForIdle(); + } + + [TestMethod] + + [Description("When the CommandBar is Disabled, the more button should be greyed out.")] + public async Task ValidateMoreButtonVisualInDisabledState() + { + TestCleanupWrapper cleanup; + + CommandBar cmdBar = null; + FontIcon ellipsisIcon = null; + Brush expectedBrushEnabled = null; + Brush expectedBrushDisabled = null; + + await RunOnUIThread(() => + { + cmdBar = new CommandBar(); + SetWindowContent(cmdBar); + + var gridResources = cmdBar.Resources; + gridResources.TryGetValue("AppBarButtonForeground", out var oExpectedBrushEnabled); + expectedBrushEnabled = oExpectedBrushEnabled as Brush; + gridResources.TryGetValue("AppBarButtonForegroundDisabled", out var oExpectedBrushDisabled); + expectedBrushDisabled = oExpectedBrushDisabled as Brush; + + }); + await WindowHelper.WaitForIdle(); + + // Verify that the ellipsis is the correct color in the Enabled CommandBar: + await RunOnUIThread(() => + { + ellipsisIcon = (FontIcon)TreeHelper.GetVisualChildByName(cmdBar, "EllipsisIcon"); + + VERIFY_ARE_EQUAL(ellipsisIcon.Foreground, expectedBrushEnabled); + + cmdBar.IsEnabled = false; + }); + await WindowHelper.WaitForIdle(); + + // Verify that the ellipsis is the correct color in the Disabled CommandBar: + await RunOnUIThread(() => VERIFY_ARE_EQUAL(ellipsisIcon.Foreground, expectedBrushDisabled)); + } + + [TestMethod] + + [Description("Validates that AppBarButtons have invisible labels when IsOpen is false.")] + public async Task ValidateAppBarButtonsHaveInvisibleLabelsWhenClosed() + { + TestCleanupWrapper cleanup; + + CommandBar cmdBar = null; + AppBarButton button = null; + TextBlock buttonLabel = null; + AppBarToggleButton toggleButton = null; + TextBlock toggleButtonLabel = null; + AppBarButton buttonSecondary = null; + TextBlock buttonSecondaryLabel = null; + AppBarToggleButton toggleButtonSecondary = null; + TextBlock toggleButtonSecondaryLabel = null; + + // Setup our environment. + await RunOnUIThread(() => + { + cmdBar = new CommandBar(); + + button = new AppBarButton(); + button.Label = "First button"; + cmdBar.PrimaryCommands.Append(button); + + toggleButton = new AppBarToggleButton(); + toggleButton.Label = "Second button"; + cmdBar.PrimaryCommands.Append(toggleButton); + + buttonSecondary = new AppBarButton(); + buttonSecondary.Label = "First button"; + cmdBar.SecondaryCommands.Append(buttonSecondary); + + toggleButtonSecondary = new AppBarToggleButton(); + toggleButtonSecondary.Label = "Second button"; + cmdBar.SecondaryCommands.Append(toggleButtonSecondary); + + SetWindowContent(cmdBar); + }); + await WindowHelper.WaitForIdle(); + + await RunOnUIThread(() => + { + buttonLabel = (TextBlock)TreeHelper.GetVisualChildByName(button, "TextLabel"); + toggleButtonLabel = (TextBlock)TreeHelper.GetVisualChildByName(toggleButton, "TextLabel"); + + VERIFY_ARE_EQUAL(buttonLabel.Visibility, Visibility.Collapsed); + VERIFY_ARE_EQUAL(toggleButtonLabel.Visibility, Visibility.Collapsed); + + cmdBar.IsOpen = true; + }); + await WindowHelper.WaitForIdle(); + + await RunOnUIThread(() => + { + // We have to wait for the overflow popup to be open to query these. + buttonSecondaryLabel = (TextBlock)TreeHelper.GetVisualChildByName(buttonSecondary, "OverflowTextLabel"); + toggleButtonSecondaryLabel = (TextBlock)TreeHelper.GetVisualChildByName(toggleButtonSecondary, "OverflowTextLabel"); + + VERIFY_ARE_EQUAL(buttonLabel.Visibility, Visibility.Visible); + VERIFY_ARE_EQUAL(toggleButtonLabel.Visibility, Visibility.Visible); + VERIFY_ARE_EQUAL(buttonSecondaryLabel.Visibility, Visibility.Visible); + VERIFY_ARE_EQUAL(toggleButtonSecondaryLabel.Visibility, Visibility.Visible); + + cmdBar.IsOpen = false; + }); + await WindowHelper.WaitForIdle(); + + await RunOnUIThread(() => + { + VERIFY_ARE_EQUAL(buttonLabel.Visibility, Visibility.Collapsed); + VERIFY_ARE_EQUAL(toggleButtonLabel.Visibility, Visibility.Collapsed); + + // Secondary buttons' label visibilities are unaffected, since the buttons aren't touched when IsOpen is false. + VERIFY_ARE_EQUAL(buttonSecondaryLabel.Visibility, Visibility.Visible); + VERIFY_ARE_EQUAL(toggleButtonSecondaryLabel.Visibility, Visibility.Visible); + }); + + } + + [TestMethod] + + [Description("Validates that AppBarButtons' text labels are offset to the right when there also are AppBarToggleButtons in the same secondary commands list.")] + public async Task ValidateAppBarButtonsAreOffsetWithAppBarToggleButtons() + { + TestCleanupWrapper cleanup; + + CommandBar cmdBar = null; + AppBarButton button = null; + TextBlock buttonLabel = null; + AppBarToggleButton toggleButton = null; + + var buttonLoadedEvent = new Event(); + var buttonUnloadedEvent = new Event(); + var toggleButtonLoadedEvent = new Event(); + var toggleButtonUnloadedEvent = new Event(); + var buttonLoadedRegistration = CreateSafeEventRegistration("Loaded"); + var buttonUnloadedRegistration = CreateSafeEventRegistration("Unloaded"); + var toggleButtonLoadedRegistration = CreateSafeEventRegistration("Loaded"); + var toggleButtonUnloadedRegistration = CreateSafeEventRegistration("Unloaded"); + + double originalAppBarButtonMargin = 0; + + // Setup our environment. + await RunOnUIThread(() => + { + cmdBar = new CommandBar(); + + button = new AppBarButton(); + button.Label = "First button"; + cmdBar.SecondaryCommands.Append(button); + + toggleButton = new AppBarToggleButton(); + toggleButton.Label = "Second button"; + + buttonLoadedRegistration.Attach(button, (s, e) => + { + LOG_OUTPUT("AppBarButton loaded."); + buttonLoadedEvent.Set(); + }); + + buttonUnloadedRegistration.Attach(button, (s, e) => + { + LOG_OUTPUT("AppBarButton unloaded."); + buttonUnloadedEvent.Set(); + }); + + toggleButtonLoadedRegistration.Attach(toggleButton, (s, e) => + { + LOG_OUTPUT("AppBarToggleButton loaded."); + toggleButtonLoadedEvent.Set(); + }); + + toggleButtonUnloadedRegistration.Attach(toggleButton, (s, e) => + { + LOG_OUTPUT("AppBarToggleButton unloaded."); + toggleButtonUnloadedEvent.Set(); + }); + + SetWindowContent(cmdBar); + }); + await buttonLoadedEvent.WaitForDefault(); + await WindowHelper.WaitForIdle(); + + await OpenCommandBar(cmdBar, OpenMethod.Programmatic); + + await RunOnUIThread(() => + { + buttonLabel = (TextBlock)TreeHelper.GetVisualChildByName(button, "OverflowTextLabel"); + originalAppBarButtonMargin = buttonLabel.Margin.Left; + cmdBar.IsOpen = false; + }); + + await buttonUnloadedEvent.WaitForDefault(); + await WindowHelper.WaitForIdle(); + + await RunOnUIThread(() => + { + cmdBar.SecondaryCommands.Append(toggleButton); + cmdBar.IsOpen = true; + }); + + await buttonLoadedEvent.WaitForDefault(); + await toggleButtonLoadedEvent.WaitForDefault(); + await WindowHelper.WaitForIdle(); + + await RunOnUIThread(() => + { + cmdBar.SecondaryCommands.RemoveAt(1); + cmdBar.IsOpen = true; + }); + + await buttonLoadedEvent.WaitForDefault(); + await WindowHelper.WaitForIdle(); + + await RunOnUIThread(() => + { + buttonLabel = (TextBlock)TreeHelper.GetVisualChildByName(button, "OverflowTextLabel"); + VERIFY_ARE_EQUAL(buttonLabel.Margin.Left, originalAppBarButtonMargin); + }); + } + + [TestMethod] + + [Description("Validates that CommandBars can be placed inline are light-dismissible.")] + [TestProperty("TestPass:ExcludeOn", "WindowsCore")] + public async Task ValidateInlineCommandBarLightDismissBehavior() + { + TestCleanupWrapper cleanup; + + Button tapTarget = null; + CommandBar cmdBar = null; + + var clickEvent = new Event(); + var openedEvent = new Event(); + var closedEvent = new Event(); + + var clickRegistration = CreateSafeEventRegistration("Click"); + var openedRegistration = CreateSafeEventRegistration>("Opened"); + var closedRegistration = CreateSafeEventRegistration>("Closed"); + + await RunOnUIThread(() => + { + tapTarget = new Button(); + tapTarget.Content = "Click Me!"; + + // Add a top margin to push the button out from under the statusbar on phone + // and a bottom margin to make sure the CommandBar doesn't open over the button. + tapTarget.Margin = ThicknessHelper.FromLengths(0, 32, 0, 32); + + cmdBar = new CommandBar(); + clickRegistration.Attach(tapTarget, (s, e) => clickEvent.Set()); + openedRegistration.Attach(cmdBar, (s, e) => openedEvent.Set()); + closedRegistration.Attach(cmdBar, (s, e) => closedEvent.Set()); + + var root = new StackPanel(); + root.Children.Append(tapTarget); + root.Children.Append(cmdBar); + SetWindowContent(root); + }); + await WindowHelper.WaitForIdle(); + + await RunOnUIThread(() => + { + cmdBar.IsOpen = true; + }); + await openedEvent.WaitForDefault(); + await WindowHelper.WaitForIdle(); + + // Click outside of the CommandBar to close it. + TestServices.InputHelper.Tap(tapTarget); + await closedEvent.WaitForDefault(); + + // Validate that sticky CommandBars are not light-dismissible. + await RunOnUIThread(() => + { + cmdBar.IsOpen = true; + cmdBar.IsSticky = true; + }); + await openedEvent.WaitForDefault(); + await WindowHelper.WaitForIdle(); + + // Click outside of the CommandBar. + TestServices.InputHelper.Tap(tapTarget); + await WindowHelper.WaitForIdle(); + + // Since the CommandBar shouldn't be light-dismissible, the button should + // have received the input and invoked its click handler. + await clickEvent.WaitForDefault(); + } + + [TestMethod] + + [Description("Validates that non-hidden CommandBars do not open on right-tap, while hidden ones do.")] + [TestProperty("TestPass:ExcludeOn", "WindowsCore")] + [TestProperty("Hosting:Mode", "UAP")] + [Ignore("MouseHelper not implemented.")] // CoreWindow pointer events no longering being raised from lifted Xaml + public async Task ValidateRightClickBehavior() + { + LOG_OUTPUT("Validating CommandBarRightClickBehavior with ClosedDisplayMode=Hidden."); + ValidateRightClickBehaviorWorker(AppBarClosedDisplayMode.Hidden); + + LOG_OUTPUT("Validating CommandBarRightClickBehavior with ClosedDisplayMode=Minimal."); + ValidateRightClickBehaviorWorker(AppBarClosedDisplayMode.Minimal); + + LOG_OUTPUT("Validating CommandBarRightClickBehavior with ClosedDisplayMode=Compact."); + ValidateRightClickBehaviorWorker(AppBarClosedDisplayMode.Compact); + } + + [TestMethod] + + [Description("Validates the CommandBar behavior for arrow key presses.")] + [TestProperty("Hosting:Mode", "UAP")] +#if __ANDROID__ || __IOS__ + [Ignore("Keyboard nav not supported")] +#endif + public async Task ValidateArrowKeys() + { + TestCleanupWrapper cleanup; + + CommandBar cmdBar = null; + Page page = null; + Button moreButton = null; + UIElement secondaryItemsPresenter = null; + var focusSequence = ""; + var expectedFocusSequence = "[M][P2][P1][P2][M][S1][S2][S4][M][S4][S2][S1][M]"; + + List> buttonGotFocusRegistrations = new List>(); + var separatorGotFocusRegistration = CreateSafeEventRegistration("GotFocus"); + var toggleButtonGotFocusRegistration = CreateSafeEventRegistration("GotFocus"); + var moreButtonGotFocusRegistration = CreateSafeEventRegistration("GotFocus"); + + var rightKeySequence = "#$d$_right#$u$_right"; + var leftKeySequence = "#$d$_left#$u$_left"; + var returnKeySequence = "#$d$_return#$u$_return"; + + int primaryCount = 0; + int secondaryCount = 0; + + RoutedEventHandler gotFocusHandler = null; + + await RunOnUIThread(() => + { + page = WindowHelper.SetupSimulatedAppPage(); + + gotFocusHandler = (s, e) => focusSequence += $"[{((FrameworkElement)s).Tag}]"; + + cmdBar = new CommandBar(); + //UNO TODO: Fix inital IsOpen load + //cmdBar.IsOpen = true; + + // Add a couple of AppBarButtons to primary + for (int i = 1; i <= 2; i++) + { + var appBarButton = new AppBarButton(); + appBarButton.Tag = "P" + i; + cmdBar.PrimaryCommands.Append(appBarButton); + + var gotFocusRegistration = CreateSafeEventRegistration("GotFocus"); + gotFocusRegistration.Attach(appBarButton, gotFocusHandler); + buttonGotFocusRegistrations.Append(gotFocusRegistration); + } + + // Add a couple of AppBarButtons to secondary + for (int i = 1; i <= 2; i++) + { + var appBarButton = new AppBarButton(); + appBarButton.Tag = "S" + i; + cmdBar.SecondaryCommands.Append(appBarButton); + + var gotFocusRegistration = CreateSafeEventRegistration("GotFocus"); + gotFocusRegistration.Attach(appBarButton, gotFocusHandler); + buttonGotFocusRegistrations.Append(gotFocusRegistration); + } + + // Add an AppBarSeparator to secondary + { + var appBarSeparator = new AppBarSeparator(); + appBarSeparator.Tag = "S3"; + cmdBar.SecondaryCommands.Append(appBarSeparator); + separatorGotFocusRegistration.Attach(appBarSeparator, gotFocusHandler); + } + + // Add an AppBarToggleButton to secondary + { + var appBarToggleButton = new AppBarToggleButton(); + appBarToggleButton.Tag = "S4"; + cmdBar.SecondaryCommands.Append(appBarToggleButton); + toggleButtonGotFocusRegistration.Attach(appBarToggleButton, gotFocusHandler); + } + + SetPageContent(cmdBar, page); + }); + await WindowHelper.WaitForIdle(); + + await RunOnUIThread(() => cmdBar.IsOpen = true); + await Task.Delay(2000); + await RunOnUIThread(() => + { + secondaryItemsPresenter = GetSecondaryItemsPresenter(cmdBar); + }); + + await RunOnUIThread(() => + { + moreButton = (Button)TreeHelper.GetVisualChildByName(cmdBar, "MoreButton"); + VERIFY_IS_NOT_NULL(moreButton); + moreButton.Tag = "M"; + moreButtonGotFocusRegistration.Attach(moreButton, gotFocusHandler); + + primaryCount = cmdBar.PrimaryCommands.Count; + secondaryCount = cmdBar.SecondaryCommands.Count; + }); + await WindowHelper.WaitForIdle(); + + focusSequence = ""; + + // Start focus with more button + await RunOnUIThread(() => moreButton.Focus(FocusState.Programmatic)); + await WindowHelper.WaitForIdle(); + + // Press left arrow key (number of primary commands + 1) times + for (int i = 0; i <= primaryCount; i++) + { + KeyboardHelper.PressKeySequence(leftKeySequence, cmdBar); + await WindowHelper.WaitForIdle(); + } + + // Press right arrow key (number of primary commands + 1) times + for (int i = 0; i <= primaryCount; i++) + { + KeyboardHelper.PressKeySequence(rightKeySequence, cmdBar); + await WindowHelper.WaitForIdle(); + } + + // Press down arrow key (number of secondary commands - 1) times + for (int i = 0; i < secondaryCount; i++) + { + KeyboardHelper.Down(i == 0 ? cmdBar : secondaryItemsPresenter); + await WindowHelper.WaitForIdle(); + } + + // Press up arrow key (number of secondary commands - 1) times + for (int i = 0; i < secondaryCount; i++) + { + KeyboardHelper.Up(i == 0 ? cmdBar : secondaryItemsPresenter); + await WindowHelper.WaitForIdle(); + } + + LOG_OUTPUT($"Expected focus sequence: {expectedFocusSequence}"); + LOG_OUTPUT($"Actual focus sequence: {focusSequence}"); + + VERIFY_ARE_EQUAL(focusSequence, expectedFocusSequence); + + await RunOnUIThread(() => + { + //page.BottomAppBar = null; + }); + } + + [TestMethod] + + [Ignore("ControlHelper.ValidateUIElementTree not implemented.")] + public async Task ValidateUIElementTreeBoth() + { + //TestCleanupWrapper cleanup; + + //LOG_OUTPUT("Validating CommandBars with both Primary & Secondary commands."); + //ControlHelper::ValidateUIElementTree( + // ValidateTreeParams( + // PopupHelper::AreWindowedPopupsEnabled() ? "Windowed" : "Unwindowed", + // wf::Size(500, 800), + // 1.f, + + // []() + + // { + // return ValidateUIElementTestSetup(true /*addPrimary*/, true /*addSecondary*/); + //}, + // GetUIElementTreeValidationRules()) + // ); + } + + [TestMethod] + + [Ignore("ControlHelper.ValidateUIElementTree not implemented.")] + public async Task ValidateUIElementTreePrimaryOnly() + { + //TestCleanupWrapper cleanup; + + //LOG_OUTPUT("Validating CommandBars with only Primary commands."); + //ControlHelper::ValidateUIElementTree( + // ValidateTreeParams( + // PopupHelper::AreWindowedPopupsEnabled() ? "Windowed" : "Unwindowed", + // wf::Size(500, 800), + // 1.f, + + // []() + + // { + // return ValidateUIElementTestSetup(true /*addPrimary*/, false /*addSecondary*/); + //}, + // GetUIElementTreeValidationRules()) + // ); + } + + [TestMethod] + + [Ignore("ControlHelper.ValidateUIElementTree not implemented.")] + public async Task ValidateUIElementTreeSecondaryOnly() + { + //TestCleanupWrapper cleanup; + + //LOG_OUTPUT("Validating CommandBars with only Secondary commands."); + //ControlHelper::ValidateUIElementTree( + // ValidateTreeParams( + // PopupHelper::AreWindowedPopupsEnabled() ? "Windowed" : "Unwindowed", + // wf::Size(500, 800), + // 1.f, + + // []() + + // { + // return ValidateUIElementTestSetup(false /*addPrimary*/, true /*addSecondary*/); + //}, + // GetUIElementTreeValidationRules()) + // ); + } + + [TestMethod] + + [Description("Validates a fix for a bug where primary command items would disappear unexpectedly.")] + [TestProperty("TestPass:ExcludeOn", "WindowsCore")] + //[Ignore] Lifted Xaml Test: Fix and re-enable tests that were disabled due to being unreliable in Helix test pass. + public async Task PrimaryCommandItemsDoNotDisappear() + { + TestCleanupWrapper cleanup; + CommandBar cmdBar = null; + + await RunOnUIThread(() => + { + var rootGrid = new Grid(); + + cmdBar = new CommandBar(); + cmdBar.VerticalAlignment = VerticalAlignment.Center; // Center it to get it out from under the statusbar. + + var appBarButton = new AppBarButton(); + appBarButton.Label = "button"; + cmdBar.PrimaryCommands.Append(appBarButton); + + rootGrid.Children.Append(cmdBar); + + SetWindowContent(rootGrid); + }); + await WindowHelper.WaitForIdle(); + + // Change the ClosedDisplayMode to Hidden. + await RunOnUIThread(() => cmdBar.ClosedDisplayMode = AppBarClosedDisplayMode.Hidden); + await WindowHelper.WaitForIdle(); + + // Open the menu. + await RunOnUIThread(() => cmdBar.IsOpen = true); + await WindowHelper.WaitForIdle(); + + // Change the ClosedDisplayMode back to Compact. + await RunOnUIThread(() => cmdBar.ClosedDisplayMode = AppBarClosedDisplayMode.Compact); + await WindowHelper.WaitForIdle(); + + // Attempt to tap the more button. + Button moreButton = null; + var clickEvent = new Event(); + var clickRegistration = CreateSafeEventRegistration("Click"); + + // Find the MoreButton and attempt to tap it. + await RunOnUIThread(() => + { + moreButton = (Button)TreeHelper.GetVisualChildByName(cmdBar, "MoreButton"); + clickRegistration.Attach(moreButton, (s, e) => clickEvent.Set()); + }); + + TestServices.InputHelper.Tap(moreButton); + await clickEvent.WaitForDefault(); + } + + [TestMethod] + + [Description("Validates that the overflow menu's scrollviewer does not scroll with arrow keys.")] + public async Task ValidateOverflowScrollViewerDoesNotScrollWithArrowKeys() + { + TestCleanupWrapper cleanup; + + CommandBar cmdBar = null; + var firstItemOriginalPosition = new Point(); + UIElement secondaryItemsPresenter = null; + + await RunOnUIThread(() => + { + cmdBar = new CommandBar(); + //UNO TODO: Fix inital IsOpen load + //cmdBar.IsOpen = true; + + for (int i = 0; i < 50; ++i) + { + var button = new AppBarButton(); + button.Label = "menu item"; + + cmdBar.SecondaryCommands.Append(button); + } + + SetWindowContent(cmdBar); + }); + await WindowHelper.WaitForIdle(); + + await RunOnUIThread(() => cmdBar.IsOpen = true); + await Task.Delay(2000); + + await RunOnUIThread(() => + { + // Focus the first element in the overflow menu. + var item = (AppBarButton)cmdBar.SecondaryCommands[0]; + item.Focus(FocusState.Keyboard); + + // Save off it's original position. + var transform = item.TransformToVisual(null); + firstItemOriginalPosition = transform.TransformPoint(new Point(0, 0)); + }); + await WindowHelper.WaitForIdle(); + + // Press down arrow key + await RunOnUIThread(() => secondaryItemsPresenter = GetSecondaryItemsPresenter(cmdBar)); + KeyboardHelper.Down(secondaryItemsPresenter); + await WindowHelper.WaitForIdle(); + + await RunOnUIThread(() => + { + var item = (AppBarButton)cmdBar.SecondaryCommands[0]; + var transform = item.TransformToVisual(null); + var firstItemNewPosition = transform.TransformPoint(new Point(0, 0)); + + VERIFY_ARE_EQUAL(firstItemNewPosition, firstItemOriginalPosition); + }); + } + + [TestMethod] + + [Description("Validates focus returns to the more button when it was previously in the overflow menu when closing.")] + [Ignore("Popup Focus not implemented")] // TODO Focus: Popups + public async Task DoesFocusReturnToMoreButtonFromOverflowMenuWhenClosed() + { + TestCleanupWrapper cleanup; + + CommandBar cmdBar = null; + + await RunOnUIThread(() => + { + cmdBar = new CommandBar(); + //UNO TODO: Fix inital IsOpen load + //cmdBar.IsOpen = true; + + var button = new AppBarButton(); + cmdBar.SecondaryCommands.Append(button); + + SetWindowContent(cmdBar); + }); + await WindowHelper.WaitForIdle(); + + await RunOnUIThread(() => cmdBar.IsOpen = true); + await Task.Delay(2000); + + await RunOnUIThread(() => + { + // Focus the first element in the overflow menu. + var item = (AppBarButton)cmdBar.SecondaryCommands[0]; + item.Focus(FocusState.Keyboard); + }); + await WindowHelper.WaitForIdle(); + + await RunOnUIThread(() => cmdBar.IsOpen = false); + await WindowHelper.WaitForIdle(); + + await RunOnUIThread(() => + { + var focusedElement = FocusManager.GetFocusedElement(WindowHelper.WindowContent.XamlRoot); + var moreButton = TreeHelper.GetVisualChildByName(cmdBar, "MoreButton"); + + VERIFY_IS_TRUE(focusedElement.Equals(moreButton)); + }); + } + + [TestMethod] + + [Description("Validates that closing a CommandBar does not result in focus being transferred to the first focusable element in the page.")] + public async Task ValidateFirstElementIsNotFocusedWhenClosingCommandBar() + { + TestCleanupWrapper cleanup; + + TextBox textBox = null; + Button button = null; + CommandBar cmdBar = null; + bool textBoxWasFocused = false; + var textBoxGotFocusRegistration = CreateSafeEventRegistration("GotFocus"); + + await RunOnUIThread(() => + { + cmdBar = new CommandBar(); + cmdBar.PrimaryCommands.Append(new AppBarButton()); + + var page = WindowHelper.SetupSimulatedAppPage(); + //page.BottomAppBar = cmdBar; + + // Add a TextBox and a Button to the page with the TextBox being the First Focusable Element. + var stackPanel = new StackPanel(); + textBox = new TextBox(); + stackPanel.Children.Append(textBox); + button = new Button(); + button.Content = "Button"; + stackPanel.Children.Append(button); + stackPanel.Children.Append(cmdBar); + SetPageContent(stackPanel, page); + + textBoxGotFocusRegistration.Attach(textBox, (s, e) => textBoxWasFocused = true); + }); + await WindowHelper.WaitForIdle(); + + await RunOnUIThread(() => + { + // Move focus to Button so it becomes the Previously Focused Element. + button.Focus(FocusState.Programmatic); + cmdBar.IsOpen = true; + }); + await WindowHelper.WaitForIdle(); + await Task.Delay(2000); + + textBoxWasFocused = false; + + await RunOnUIThread(() => cmdBar.IsOpen = false); + await WindowHelper.WaitForIdle(); + + // Verify that the focus did not move to the First Focusable Element. + VERIFY_IS_FALSE(textBoxWasFocused); + } + + [TestMethod] + + [Description("Validates that focused command bar elements stay focused after a collection or size change.")] + [Ignore("Popup Focus is buggy.")] + public async Task CanMaintainFocusAfterCollectionOrSizeChange() + { + TestCleanupWrapper cleanup; + + CommandBar commandBar = null; + + Action> addButton = (label, commands) => + { + var button = new AppBarButton(); + button.Label = label; + commands.Append(button); + }; + + await RunOnUIThread(() => + { + commandBar = new CommandBar(); + commandBar.IsDynamicOverflowEnabled = false; + //commandBar.IsOpen = true; + commandBar.IsSticky = true; + commandBar.Width = 500; + + for (int i = 0; i < 3; ++i) + { + addButton("Primary Item #" + i.ToString(), commandBar.PrimaryCommands); + addButton("Secondary Item #" + i.ToString(), commandBar.SecondaryCommands); + } + + SetWindowContent(commandBar); + }); + await WindowHelper.WaitForIdle(); + + //UNO TOOD: Fix IsOpen initial load + await RunOnUIThread(() => commandBar.IsOpen = true); + await Task.Delay(2000); + + await RunOnUIThread(() => + { + LOG_OUTPUT("Focus the second primary command."); + ((Control)commandBar.PrimaryCommands.GetAt(1)).Focus(FocusState.Keyboard); + + LOG_OUTPUT("Add new primary command."); + addButton("Added Primary Item", commandBar.PrimaryCommands); + }); + await WindowHelper.WaitForIdle(); + + await RunOnUIThread(() => + { + LOG_OUTPUT("Validate the second primary command still has focus."); + VERIFY_ARE_EQUAL(commandBar.PrimaryCommands.GetAt(1), (ICommandBarElement)FocusManager.GetFocusedElement(WindowHelper.WindowContent.XamlRoot)); + + LOG_OUTPUT("Focus the second secondary command."); + ((Control)commandBar.SecondaryCommands.GetAt(1)).Focus(FocusState.Keyboard); + + LOG_OUTPUT("Add new secondary command."); + addButton("Added Secondary Item", commandBar.SecondaryCommands); + }); + await WindowHelper.WaitForIdle(); + + await RunOnUIThread(() => + { + LOG_OUTPUT("Validate the second secondary command still has focus."); + VERIFY_ARE_EQUAL(commandBar.SecondaryCommands.GetAt(1), (ICommandBarElement)(FocusManager.GetFocusedElement(WindowHelper.WindowContent.XamlRoot))); + + LOG_OUTPUT("Clearing all secondary commands. Focus is expected to go to the more button."); + commandBar.SecondaryCommands.Clear(); + }); + await WindowHelper.WaitForIdle(); + await Task.Delay(2000); + await RunOnUIThread(() => + { + LOG_OUTPUT("Validate the more button has focus."); + var moreButton = (Button)(TreeHelper.GetVisualChildByName(commandBar, "MoreButton")); + var focused = (Button)FocusManager.GetFocusedElement(WindowHelper.WindowContent.XamlRoot); + VERIFY_ARE_EQUAL(moreButton, focused); + + LOG_OUTPUT("Focus fourth primary command, enable dynamic overflow and resize command bar."); + ((Control)commandBar.PrimaryCommands.GetAt(3)).Focus(FocusState.Keyboard); + commandBar.IsDynamicOverflowEnabled = true; + commandBar.Width = 250; + }); + await WindowHelper.WaitForIdle(); + + await RunOnUIThread(() => + { + LOG_OUTPUT("Fourth primary command is now in the secondary ItemsControl. Validate it still has focus."); + VERIFY_ARE_EQUAL(commandBar.PrimaryCommands.GetAt(3), (ICommandBarElement)(FocusManager.GetFocusedElement(WindowHelper.WindowContent.XamlRoot))); + + LOG_OUTPUT("Resize command bar back to its original size."); + commandBar.Width = 500; + }); + await WindowHelper.WaitForIdle(); + + await RunOnUIThread(() => + { + LOG_OUTPUT("Fourth primary command is back in the primary ItemsControl. Validate it still has focus."); + VERIFY_ARE_EQUAL(commandBar.PrimaryCommands.GetAt(3), (ICommandBarElement)(FocusManager.GetFocusedElement(WindowHelper.WindowContent.XamlRoot))); + }); + } + + [TestMethod] + + [Description("Validates that setting CommandBar.IsOpen = true in Closed does not permanently hide labels and the overflow popup as though the CommandBar were still closed.")] + [TestProperty("Hosting:Mode", "UAP")] + public async Task CanReopenInClosedHandler() + { + TestCleanupWrapper cleanup; + + CommandBar cmdBar = null; + AppBarButton appBarButton = null; + var commandBarClosedRegistration = CreateSafeEventRegistration>("Closed"); + + await RunOnUIThread(() => + { + cmdBar = new CommandBar(); + appBarButton = new AppBarButton(); + cmdBar.PrimaryCommands.Append(appBarButton); + commandBarClosedRegistration.Attach(cmdBar, (s, e) => ((CommandBar)s).IsOpen = true); + + var page = WindowHelper.SetupSimulatedAppPage(); + SetPageContent(cmdBar, page); + //page.BottomAppar = cmdBar; + }); + + await RunOnUIThread(() => cmdBar.IsOpen = true); + await WindowHelper.WaitForIdle(); + + await RunOnUIThread(() => cmdBar.IsOpen = false); + await WindowHelper.WaitForIdle(); + + await RunOnUIThread(() => + { + VERIFY_IS_TRUE(cmdBar.IsOpen); + VERIFY_IS_FALSE(appBarButton.IsCompact); + + var overflowPopup = (Popup)TreeHelper.GetVisualChildByName(cmdBar, "OverflowPopup"); + + VERIFY_IS_TRUE(overflowPopup.IsOpen); + + // We need to close the popup at the end of this test, + // and without detaching our event handler, closing it + // is just going to cause it to re-open again. + // So we need to detach the event handler here. + commandBarClosedRegistration.Detach(); + + cmdBar.IsOpen = false; + }); + await WindowHelper.WaitForIdle(); + } + + [TestMethod] + + [Description("Validates that tabbing will not focus the CommandBar when it's ClosedDisplayMode=Hidden and it's closed.")] + [Ignore("Popup focus is buggy")] + public async Task CanNotTabIntoWhenClosedAndHidden() + { + TestCleanupWrapper cleanup; + + Button button = null; + CommandBar cmdBar = null; + + var cmdBarGotFocusRegistration = CreateSafeEventRegistration("GotFocus"); + bool didCmdBarGetFocus = false; + + await RunOnUIThread(() => + { + cmdBar = new CommandBar(); + cmdBar.ClosedDisplayMode = AppBarClosedDisplayMode.Hidden; + + // Add some content to make sure it doesn't get focus either. + cmdBar.PrimaryCommands.Append(new AppBarButton()); + + cmdBarGotFocusRegistration.Attach(cmdBar, (s, e) => didCmdBarGetFocus = true); + + button = new Button(); + button.Content = "button"; + + var root = new Grid(); + root.Children.Append(button); + root.Children.Append(cmdBar); + + SetWindowContent(root); + }); + await WindowHelper.WaitForIdle(); + + await RunOnUIThread(() => + { + button.Focus(FocusState.Programmatic); + }); + await WindowHelper.WaitForIdle(); + + await SimulateTabAsync(WindowHelper.WindowContent); + await WindowHelper.WaitForIdle(); + + VERIFY_IS_FALSE(didCmdBarGetFocus); + } + + [TestMethod] + + [Description("Validates that the overflow menu is not shown when all the items are Collapsed.")] + public async Task DoesNotShowMenuIfSecondaryElementsAreCollapsed() + { + TestCleanupWrapper cleanup; + + var loadedEvent = new Event(); + var loadedRegistration = CreateSafeEventRegistration("Loaded"); + + CommandBar cmdBar = null; + + await RunOnUIThread(() => + { + var collapsedAppBarButton = new AppBarButton(); + collapsedAppBarButton.Visibility = Visibility.Collapsed; + + var collapsedAppBarSeparator = new AppBarSeparator(); + collapsedAppBarSeparator.Visibility = Visibility.Collapsed; + + var collapsedAppBarToggleButton = new AppBarToggleButton(); + collapsedAppBarToggleButton.Visibility = Visibility.Collapsed; + + cmdBar = new CommandBar(); + //cmdBar.IsOpen = true; + cmdBar.SecondaryCommands.Append(collapsedAppBarButton); + cmdBar.SecondaryCommands.Append(collapsedAppBarSeparator); + cmdBar.SecondaryCommands.Append(collapsedAppBarToggleButton); + + loadedRegistration.Attach(cmdBar, (s, e) => + { + LOG_OUTPUT("CommandBar.Loaded raised."); + loadedEvent.Set(); + }); + + SetWindowContent(cmdBar); + }); + + await loadedEvent.WaitForDefault(); + await WindowHelper.WaitForIdle(); + + //UNO TODO: IsOpen on load + await RunOnUIThread(() => cmdBar.IsOpen = true); + await Task.Delay(2000); + + await RunOnUIThread(() => + { + var overflowContentRoot = (UIElement)TreeHelper.GetVisualChildByNameFromOpenPopups("OverflowContentRoot", cmdBar); + VERIFY_IS_NOT_NULL(overflowContentRoot); + + VERIFY_ARE_EQUAL(overflowContentRoot.Visibility, Visibility.Collapsed); + }); + } + + [TestMethod] + [Description("Validates that the CommandBar opens down/up based on the available space inside the layout bounds.")] +#if __ANDROID__ + [Ignore("CommandBar popup measure glitch with fullscreen")] +#endif + public async Task ValidateCommandBarOpensInsideLayoutBounds() + { + TestCleanupWrapper cleanup; + + await ValidateInlineCommandBarOpenDirection(VerticalAlignment.Top); + await ValidateInlineCommandBarOpenDirection(VerticalAlignment.Center); + await ValidateInlineCommandBarOpenDirection(VerticalAlignment.Bottom); + } + + private async Task ValidateInlineCommandBarOpenDirection(VerticalAlignment alignment) + { + CommandBar commandBar = null; + Page page = null; + + await RunOnUIThread(() => + { + page = WindowHelper.SetupSimulatedAppPage(); + commandBar = new CommandBar(); + commandBar.VerticalAlignment = alignment; + commandBar.PrimaryCommands.Append(new AppBarButton()); + commandBar.SecondaryCommands.Append(new AppBarButton()); + commandBar.SecondaryCommands.Append(new AppBarButton()); + Grid grid = new Grid(); + grid.Children.Append(commandBar); + SetPageContent(grid, page); + }); + await WindowHelper.WaitForIdle(); + + await OpenCommandBar(commandBar, OpenMethod.Programmatic); + + UIElement overflowContentRoot = null; + + await RunOnUIThread(() => overflowContentRoot = TreeHelper.GetVisualChildByNameFromOpenPopups("OverflowContentRoot", commandBar)); + await WindowHelper.WaitForIdle(); + + Rect commandBarBounds = await ControlHelper.GetBounds(commandBar); + Rect commandBarOverflowBounds = await ControlHelper.GetBounds((FrameworkElement)overflowContentRoot); + + LOG_OUTPUT($"commandBarBounds: ({commandBarBounds.X}, {commandBarBounds.Y}, {commandBarBounds.Width}, {commandBarBounds.Height})"); + LOG_OUTPUT($"commandBarOverflowBounds: ({commandBarOverflowBounds.X}, {commandBarOverflowBounds.Y}, {commandBarOverflowBounds.Width}, {commandBarOverflowBounds.Height})"); + + //Test that the CommandBarOverflow is positioned correctly + switch (alignment) + { + case VerticalAlignment.Top: + VERIFY_IS_TRUE(commandBarOverflowBounds.Y >= commandBarBounds.Y); + break; + case VerticalAlignment.Center: + VERIFY_IS_TRUE(commandBarOverflowBounds.Y < commandBarBounds.Y); + break; + case VerticalAlignment.Bottom: + VERIFY_IS_TRUE(commandBarOverflowBounds.Y < commandBarBounds.Y); + break; + } + } + + [TestMethod] + + [Description("Validates that after clicking on an AppBarButton, the CommandBar closes before the button's click handlers execute.")] + [TestProperty("TestPass:ExcludeOn", "WindowsCore")] + public async Task DoesCloseBeforeButtonClickHandlersExecute() + { + + } + + [TestMethod] + + [Description("Validates CommandBar cycles focus when open.")] + [TestProperty("Hosting:Mode", "UAP")] + [Ignore("Focus bug with Shift-Tab in Popups.")] + public async Task DoesCycleFocusWhenOpen() + { + var expectedFocusSequence = "[S1][P1][P2][P3][M][P3][P2][P1][S1][M]"; + await DoesCycleFocusWhenOpenWorker(Location.Inline, 5, expectedFocusSequence); + // await DoesCycleFocusWhenOpenWorker(Location.Top, 5, expectedFocusSequence); + // await DoesCycleFocusWhenOpenWorker(Location.Bottom, 5, expectedFocusSequence); + } + + private async Task DoesCycleFocusWhenOpenWorker(Location location, int numTabs, string expectedFocusSequence) + { + TestCleanupWrapper cleanup; + + Page page = null; + StackPanel panel = null; + CommandBar cmdBar = null; + UIElement secondaryItemsPresenter = null; + + var pageLoadedEvent = new Event(); + var moreButtonGotFocusEvent = new Event(); + var pageLoadedRegistration = CreateSafeEventRegistration("Loaded"); + var buttonGotFocusRegistration = CreateSafeEventRegistration("GotFocus"); + var moreButtonGotFocusRegistration = CreateSafeEventRegistration("GotFocus"); + var commandBarGotFocusRegistration = CreateSafeEventRegistration("GotFocus"); + var overflowGotFocusRegistration = CreateSafeEventRegistration("GotFocus"); + + var focusSequence = ""; + RoutedEventHandler gotFocusHandler = null; + + await RunOnUIThread(() => + { + gotFocusHandler = (s, e) => + { + focusSequence += $"[{((FrameworkElement)e.OriginalSource).Tag}]"; + }; + + page = WindowHelper.SetupSimulatedAppPage(); + pageLoadedRegistration.Attach(page, (s, e) => pageLoadedEvent.Set()); + + panel = new StackPanel(); + + var button = new Button(); + button.Content = "Button"; + button.Tag = "B"; + buttonGotFocusRegistration.Attach(button, gotFocusHandler); + panel.Children.Append(button); + + cmdBar = (CommandBar)XamlReader.Load(@" + + + + + + + + + + + "); + commandBarGotFocusRegistration.Attach(cmdBar, gotFocusHandler); + + switch (location) + { + case Location.Inline: + panel.Children.Append(cmdBar); + break; + case Location.Top: + //TODO: TopAppBar not implemented + //page.TopAppBar = cmdBar; + break; + case Location.Bottom: + //TODO: BottomAppBar not implemented + //page.BottomAppBar = cmdBar; + break; + } + + SetPageContent(panel, page); + }); + await pageLoadedEvent.WaitForDefault(); + await WindowHelper.WaitForIdle(); + + await RunOnUIThread(() => + { + // Start with the focus on the moreButton. + var moreButton = (Button)TreeHelper.GetVisualChildByName(cmdBar, "MoreButton"); + moreButton.Tag = "M"; + moreButtonGotFocusRegistration.Attach(moreButton, (s, e) => moreButtonGotFocusEvent.Set()); + moreButton.Focus(FocusState.Keyboard); + + cmdBar.IsOpen = true; + }); + await moreButtonGotFocusEvent.WaitForDefault(); + await WindowHelper.WaitForIdle(); + + await Task.Delay(2000); + + focusSequence = ""; + + await RunOnUIThread(() => + { + var overflowContentRoot = (UIElement)TreeHelper.GetVisualChildByNameFromOpenPopups("OverflowContentRoot", panel); + secondaryItemsPresenter = GetSecondaryItemsPresenter(cmdBar); + overflowGotFocusRegistration.Attach(overflowContentRoot, gotFocusHandler); + }); + + // Tab several times to cycle focus through the CommandBar. + for (int i = 0; i < numTabs; ++i) + { + KeyboardHelper.Tab(i == 1 ? secondaryItemsPresenter : cmdBar); + await WindowHelper.WaitForIdle(); + } + + // Shift-Tab several times to cycle focus through the CommandBar in reverse. + for (int i = 0; i < numTabs; ++i) + { + KeyboardHelper.ShiftTab(i == (numTabs - 1) ? secondaryItemsPresenter : cmdBar); + await WindowHelper.WaitForIdle(); + } + + LOG_OUTPUT($"Expected focus sequence: {expectedFocusSequence}"); + LOG_OUTPUT($"Actual focus sequence: {focusSequence}"); + VERIFY_ARE_EQUAL(focusSequence, expectedFocusSequence); + + await EmptyPageContent(page); + } + + [TestMethod] + + [Description("Validates that a user can tab into the CommandBar's overflow menu when set as a Top/Bottom AppBar.")] + [Ignore("TopAppBar/BottomAppBar not implemented.")] + + public async Task CanTabIntoOverflowMenuWhenTopOrBottom() + { + TestCleanupWrapper cleanup; + + Page page = null; + CommandBar cmdBar = null; + AppBarButton appBarButton = null; + + await RunOnUIThread(() => + { + cmdBar = new CommandBar(); + appBarButton = new AppBarButton(); + + cmdBar.SecondaryCommands.Append(appBarButton); + + page = WindowHelper.SetupSimulatedAppPage(); + + //TODO: TopAppBar not implemented + //page.TopAppBar = cmdBar; + + SetWindowContent(page); + }); + await WindowHelper.WaitForIdle(); + + await RunOnUIThread(() => cmdBar.IsOpen = true); + await WindowHelper.WaitForIdle(); + + // Tab once to move into the overflow menu. + KeyboardHelper.Tab(WindowHelper.WindowContent); + await WindowHelper.WaitForIdle(); + + await RunOnUIThread(() => + { + VERIFY_IS_TRUE(FocusManager.GetFocusedElement(WindowHelper.WindowContent.XamlRoot).Equals(appBarButton)); + + cmdBar.IsOpen = false; + + page.TopAppBar = null; + //TODO: BottomAppBar not implemented + //page.BottomAppBar = cmdBar; + }); + await WindowHelper.WaitForIdle(); + + await RunOnUIThread(() => cmdBar.IsOpen = true); + await WindowHelper.WaitForIdle(); + + // Tab once to move into the overflow menu. + KeyboardHelper.Tab(WindowHelper.WindowContent); + await WindowHelper.WaitForIdle(); + + await RunOnUIThread(() => + { + VERIFY_IS_TRUE(FocusManager.GetFocusedElement(WindowHelper.WindowContent.XamlRoot).Equals(appBarButton)); + + cmdBar.IsOpen = false; + }); + } + + [TestMethod] + + [Description("Validates that a minimal closed command bar with only secondary commands is visible.")] + [TestProperty("TestPass:ExcludeOn", "WindowsCore")] + public async Task ValidateClosedMinimalCommandBarWithSecondaryCommandsOnlyIsVisible() + { + TestCleanupWrapper cleanup; + + CommandBar commandBar = null; + + var openedEvent = new Event(); + var openedRegistration = CreateSafeEventRegistration>("Opened"); + + FrameworkElement moreButton = null; + + await RunOnUIThread(() => + { + commandBar = new CommandBar(); + commandBar.ClosedDisplayMode = AppBarClosedDisplayMode.Minimal; + commandBar.VerticalAlignment = VerticalAlignment.Center; // Center it to get it out from under the status bar. + openedRegistration.Attach(commandBar, (s, e) => openedEvent.Set()); + + // Add secondary commands + var appBarButton = new AppBarButton(); + commandBar.SecondaryCommands.Append(appBarButton); + + var rootPanel = new Grid(); + rootPanel.Children.Append(commandBar); + SetWindowContent(rootPanel); + }); + await WindowHelper.WaitForIdle(); + + // Try tapping the more button + await RunOnUIThread(() => moreButton = (FrameworkElement)TreeHelper.GetVisualChildByName(commandBar, "MoreButton")); + TestServices.InputHelper.Tap(moreButton); + await openedEvent.WaitForDefault(); + } + + //-------------------------------------------------------------------------------------- + // Test case: Verifies that once you enter a bottom commandbar overflow, + // you can exit it by pressing Escape when the focus is on an overflow item + //-------------------------------------------------------------------------------------- + [TestMethod] + + [Description("Verifies that once you enter a bottom commandbar overflow, you can exit it by pressing Escape and focus is restored to the Expand Button.")] + [Ignore("BottomAppBar not implemented.")] + public async Task DoesFocusExpandButtonWithOverflowEscKey() + { + TestCleanupWrapper cleanup; + UIElement secondaryItemsPresenter = null; + Page rootPage = (Page)XamlReader.Load(@" + + + + + + + + + + + + + + + "); + + flyoutButton = (Button)root.FindName("FlyoutButton"); + commandBarFlyout = (Flyout)flyoutButton.Flyout; + commandBar = (CommandBar)commandBarFlyout.Content; + menuFlyoutAppBarButton1 = (AppBarButton)commandBar.SecondaryCommands.GetAt(0); + menuFlyout1 = (MenuFlyout)menuFlyoutAppBarButton1.Flyout; + menuFlyoutItem1 = (MenuFlyoutItem)menuFlyout1.Items[0]; + menuFlyoutAppBarButton2 = (AppBarButton)commandBar.SecondaryCommands.GetAt(1); + menuFlyout2 = (MenuFlyout)menuFlyoutAppBarButton2.Flyout; + menuFlyoutSubItem = (MenuFlyoutSubItem)menuFlyout2.Items[0]; + menuFlyoutItem2 = (MenuFlyoutItem)menuFlyoutSubItem.Items[0]; + menuFlyoutAppBarButton3 = (AppBarButton)commandBar.SecondaryCommands.GetAt(2); + menuFlyout3 = (MenuFlyout)menuFlyoutAppBarButton3.Flyout; + menuFlyoutItem3 = (MenuFlyoutItem)menuFlyout3.Items[0]; + appBarButtonWithoutFlyout = (AppBarButton)commandBar.SecondaryCommands.GetAt(3); + appBarToggleButton = (AppBarToggleButton)commandBar.SecondaryCommands.GetAt(4); + + commandBarOpenedEventRegistration.Attach(commandBar, (s, e) => + { + LOG_OUTPUT("CommandBar opened."); + commandBarOpenedEvent.Set(); + }); + + commandBarClosedEventRegistration.Attach(commandBar, (s, e) => + { + LOG_OUTPUT("CommandBar closed."); + commandBarClosedEvent.Set(); + }); + + menuFlyoutAppBarButton1LoadedEventRegistration.Attach(menuFlyoutAppBarButton1, (s, e) => + { + LOG_OUTPUT("MenuFlyoutAppBarButton1 loaded."); + menuFlyoutAppBarButton1LoadedEvent.Set(); + }); + + menuFlyoutItem1ClickEventRegistration.Attach(menuFlyoutItem1, (s, e) => + { + LOG_OUTPUT("MenuFlyoutItem1 clicked."); + menuFlyoutItem1ClickEvent.Set(); + }); + + menuFlyoutItem2ClickEventRegistration.Attach(menuFlyoutItem2, (s, e) => + { + LOG_OUTPUT("MenuFlyoutItem2 clicked."); + menuFlyoutItem2ClickEvent.Set(); + }); + + menuFlyout1OpenedEventRegistration.Attach(menuFlyout1, (s, e) => + { + LOG_OUTPUT("MenuFlyout1 opened."); + menuFlyout1OpenedEvent.Set(); + }); + + menuFlyout1ClosedEventRegistration.Attach(menuFlyout1, (s, e) => + { + LOG_OUTPUT("MenuFlyout1 closed."); + menuFlyout1ClosedEvent.Set(); + }); + + menuFlyout2OpenedEventRegistration.Attach(menuFlyout2, (s, e) => + { + LOG_OUTPUT("MenuFlyout2 opened."); + menuFlyout2OpenedEvent.Set(); + }); + + menuFlyout2ClosedEventRegistration.Attach(menuFlyout2, (s, e) => + { + LOG_OUTPUT("MenuFlyout2 closed."); + menuFlyout2ClosedEvent.Set(); + }); + + menuFlyout3OpenedEventRegistration.Attach(menuFlyout3, (s, e) => + { + LOG_OUTPUT("MenuFlyout3 opened."); + menuFlyout3OpenedEvent.Set(); + }); + + menuFlyout3ClosedEventRegistration.Attach(menuFlyout3, (s, e) => + { + LOG_OUTPUT("MenuFlyout3 closed."); + menuFlyout3ClosedEvent.Set(); + }); + + SetPageContent(root, page); + + }); + + + await WindowHelper.WaitForIdle(); + + FlyoutHelper.OpenFlyout(commandBarFlyout, flyoutButton, FlyoutOpenMethod.Programmatic_ShowAt); + + // Since the CommandBar starts with IsOpen already true, we don't get an Opened event the first time. + // We'll listen for the loaded event on MenuFlyoutAppBarButton1 instead. + await menuFlyoutAppBarButton1LoadedEvent.WaitForDefault(); + await TestServices.WindowHelper.WaitForIdle(); + + LOG_OUTPUT("Moving mouse over MenuFlyoutAppBarButton1, which should open the first menu flyout."); + TestServices.InputHelper.MoveMouse(menuFlyoutAppBarButton1); + await menuFlyout1OpenedEvent.WaitForDefault(); + await TestServices.WindowHelper.WaitForIdle(); + + LOG_OUTPUT("Clicking on the MenuFlyoutItem, which should close both the menu flyout and the CommandBar."); + TestServices.InputHelper.LeftMouseClick(menuFlyoutItem1); + await menuFlyoutItem1ClickEvent.WaitForDefault(); + await commandBarClosedEvent.WaitForDefault(); + await TestServices.WindowHelper.WaitForIdle(); + + await RunOnUIThread(() => + { + commandBar.IsOpen = true; + }); + + await commandBarOpenedEvent.WaitForDefault(); + await TestServices.WindowHelper.WaitForIdle(); + + LOG_OUTPUT("Moving mouse over MenuFlyoutAppBarButton2, which should close the first menu flyout and open the second."); + TestServices.InputHelper.MoveMouse(menuFlyoutAppBarButton2); + await menuFlyout1ClosedEvent.WaitForDefault(); + await menuFlyout2OpenedEvent.WaitForDefault(); + await TestServices.WindowHelper.WaitForIdle(); + + LOG_OUTPUT("Moving mouse over MenuFlyoutSubItem, which should open the sub-menu."); + TestServices.InputHelper.MoveMouse(menuFlyoutSubItem); + // Wait for the sub menu to open. It opens after a delay - clicking and waiting for idle doesn't open it. + // tracks this bug. + await TestServices.WindowHelper.SynchronouslyTickUIThread(60); + await TestServices.WindowHelper.WaitForIdle(); + + LOG_OUTPUT("Clicking on the MenuFlyoutItem, which should close both the menu flyout and the CommandBar."); + TestServices.InputHelper.LeftMouseClick(menuFlyoutItem2); + await menuFlyoutItem2ClickEvent.WaitForDefault(); + await menuFlyout2ClosedEvent.WaitForDefault(); + await commandBarClosedEvent.WaitForDefault(); + await TestServices.WindowHelper.WaitForIdle(); + + await RunOnUIThread(() => + { + commandBar.IsOpen = true; + }); + + await commandBarOpenedEvent.WaitForDefault(); + await TestServices.WindowHelper.WaitForIdle(); + + LOG_OUTPUT("Moving mouse over MenuFlyoutAppBarButton3, which should open the third menu flyout."); + TestServices.InputHelper.MoveMouse(menuFlyoutAppBarButton3); + await menuFlyout3OpenedEvent.WaitForDefault(); + await TestServices.WindowHelper.WaitForIdle(); + + LOG_OUTPUT("Moving mouse over MenuFlyoutItem3, then over AppBarButtonWithoutFlyout, which should close the third menu flyout."); + TestServices.InputHelper.MoveMouse(menuFlyoutItem3); + await TestServices.WindowHelper.WaitForIdle(); + TestServices.InputHelper.MoveMouse(appBarButtonWithoutFlyout); + await menuFlyout3ClosedEvent.WaitForDefault(); + await TestServices.WindowHelper.WaitForIdle(); + + LOG_OUTPUT("Moving mouse over MenuFlyoutAppBarButton3, which should open the third menu flyout."); + TestServices.InputHelper.MoveMouse(menuFlyoutAppBarButton3); + await menuFlyout3OpenedEvent.WaitForDefault(); + await TestServices.WindowHelper.WaitForIdle(); + + LOG_OUTPUT("Moving mouse over MenuFlyoutItem3, then over AppBarToggleButton, which should close the third menu flyout."); + TestServices.InputHelper.MoveMouse(menuFlyoutItem3); + await TestServices.WindowHelper.WaitForIdle(); + TestServices.InputHelper.MoveMouse(appBarToggleButton); + await menuFlyout3ClosedEvent.WaitForDefault(); + await TestServices.WindowHelper.WaitForIdle(); + + await RunOnUIThread(() => + { + commandBar.IsOpen = false; + }); + + await commandBarClosedEvent.WaitForDefault(); + await TestServices.WindowHelper.WaitForIdle(); + + FlyoutHelper.HideFlyout(commandBarFlyout); + } + + [TestMethod] + + [Description("Verify that setting the Flyout property on an AppBarButton and then showing that flyout does not display a light-dismiss layer that prevents interaction with the rest of the CommandBar.")] + [TestProperty("TestPass:ExcludeOn", "WindowsCore")] + [Ignore("InputHelper.MoveMouse not implemented.")] + public async Task VerifySubMenuDoesNotEatPointerInput() + { + TestCleanupWrapper cleanup; + + CommandBar commandBar = null; + AppBarButton flyoutAppBarButton = null; + AppBarButton otherAppBarButton = null; + + var commandBarOpenedEvent = new Event(); + var commandBarOpenedEventRegistration = CreateSafeEventRegistration>("Opened"); + var commandBarClosedEvent = new Event(); + var commandBarClosedEventRegistration = CreateSafeEventRegistration>("Closed"); + var menuFlyoutOpenedEvent = new Event(); + var menuFlyoutOpenedEventRegistration = CreateSafeEventRegistration("Opened"); + var menuFlyoutClosedEvent = new Event(); + var menuFlyoutClosedEventRegistration = CreateSafeEventRegistration("Closed"); + + await RunOnUIThread(() => + { + var page = TestServices.WindowHelper.SetupSimulatedAppPage(); + + var root = (Grid)(XamlReader.Load( + @" + + + + + + + + + + + + + ")); + + + commandBar = (CommandBar)(root.FindName("CommandBar")); + flyoutAppBarButton = (AppBarButton)(root.FindName("FlyoutAppBarButton")); + otherAppBarButton = (AppBarButton)(root.FindName("OtherAppBarButton")); + + var menuFlyout = (MenuFlyout)(root.FindName("MenuFlyout")); + + commandBarOpenedEventRegistration.Attach(commandBar, (s, e) => { commandBarOpenedEvent.Set(); }); + commandBarClosedEventRegistration.Attach(commandBar, (s, e) => { commandBarClosedEvent.Set(); }); + menuFlyoutOpenedEventRegistration.Attach(menuFlyout, (s, e) => { menuFlyoutOpenedEvent.Set(); }); + menuFlyoutClosedEventRegistration.Attach(menuFlyout, (s, e) => { menuFlyoutClosedEvent.Set(); }); + + SetPageContent(root, page); + }); + + await TestServices.WindowHelper.WaitForIdle(); + + await RunOnUIThread(() => + + { + commandBar.IsOpen = true; + }); + + await commandBarOpenedEvent.WaitForDefault(); + await TestServices.WindowHelper.WaitForIdle(); + + LOG_OUTPUT("Moving mouse over FlyoutAppBarButton, which should open the flyout."); + TestServices.InputHelper.MoveMouse(flyoutAppBarButton); + await menuFlyoutOpenedEvent.WaitForDefault(); + await TestServices.WindowHelper.WaitForIdle(); + + LOG_OUTPUT("Moving mouse over OtherAppBarButton, which should close the flyout."); + TestServices.InputHelper.MoveMouse(otherAppBarButton); + await menuFlyoutClosedEvent.WaitForDefault(); + await TestServices.WindowHelper.WaitForIdle(); + + await RunOnUIThread(() => + + { + commandBar.IsOpen = false; + }); + + await commandBarClosedEvent.WaitForDefault(); + await TestServices.WindowHelper.WaitForIdle(); + } + + + [TestMethod] + + [Description("Verify that setting the Flyout property on a primary AppBarButton does not cause that flyout to cease to have a light-dismiss layer.")] + [TestProperty("TestPass:ExcludeOn", "WindowsCore")] + [Ignore("InputHelper.Tap(Point) not implemented.")] + public async Task VerifySubMenuHasLightDismissOnPrimaryAppBarButton() + { + TestCleanupWrapper cleanup; + + CommandBar commandBar = null; + AppBarButton flyoutAppBarButton = null; + + var menuFlyoutOpenedEvent = new Event(); + var menuFlyoutOpenedEventRegistration = CreateSafeEventRegistration("Opened"); + var menuFlyoutClosedEvent = new Event(); + var menuFlyoutClosedEventRegistration = CreateSafeEventRegistration("Closed"); + + await RunOnUIThread(() => + { + var page = TestServices.WindowHelper.SetupSimulatedAppPage(); + + var root = (Grid)(XamlReader.Load( + @"( + + + + + + + + + + )")); + + commandBar = (CommandBar)(root.FindName("CommandBar")); + flyoutAppBarButton = (AppBarButton)(root.FindName("FlyoutAppBarButton")); + + var menuFlyout = (MenuFlyout)(root.FindName("MenuFlyout")); + + menuFlyoutOpenedEventRegistration.Attach(menuFlyout, (s, e) => { menuFlyoutOpenedEvent.Set(); }); + menuFlyoutClosedEventRegistration.Attach(menuFlyout, (s, e) => { menuFlyoutClosedEvent.Set(); }); + + SetPageContent(root, page); + }); + + await TestServices.WindowHelper.WaitForIdle(); + + LOG_OUTPUT("Tapping on FlyoutAppBarButton, which should open the flyout."); + TestServices.InputHelper.Tap(flyoutAppBarButton); + await menuFlyoutOpenedEvent.WaitForDefault(); + await TestServices.WindowHelper.WaitForIdle(); + + LOG_OUTPUT("Tapping in empty space, which should close the flyout."); + TestServices.InputHelper.Tap(new Point(300, 300)); + await menuFlyoutClosedEvent.WaitForDefault(); + await TestServices.WindowHelper.WaitForIdle(); + } + + private async Task ValidateDynamicOverflowOrderWorker(CommandBar cmdBar, DynamicOverflowOrderTest orderTestCase) + { + await OpenCommandBar(cmdBar, OpenMethod.Programmatic); + + await RunOnUIThread(() => + { + var primaryItemsControl = (ItemsControl)TreeHelper.GetVisualChildByName(cmdBar, "PrimaryItemsControl"); + var primaryItems = primaryItemsControl.Items; + int primaryItemsCount = primaryItems.Count; + + var overflowContentRoot = (FrameworkElement)TreeHelper.GetVisualChildByNameFromOpenPopups("OverflowContentRoot", cmdBar); + var secondaryItemsControl = (ItemsControl)TreeHelper.GetVisualChildByName(overflowContentRoot, "SecondaryItemsControl"); + var secondaryItems = secondaryItemsControl.Items; + int secondaryCount = secondaryItems.Count; + + LOG_OUTPUT($"Primary items counts : {primaryItemsCount}"); + LOG_OUTPUT($"Secondary items counts : {secondaryCount}"); + + switch (orderTestCase) + { + case DynamicOverflowOrderTest.OrderTestForAlternativeValue: // Test for alternative order - {1,2,1,2,1,2,1,2,1,2} + { + for (int i = 0; i < 10; i++) + { + if (i % 2 == 0) + { + var button = (AppBarButton)(cmdBar.PrimaryCommands.GetAt(i)); + VERIFY_IS_TRUE(button.IsInOverflow); + } + } + break; + } + case DynamicOverflowOrderTest.OrderTestForAllSameValue: // Test for all same order - {1,1,1,1,1,1,1,1,1,1} + { + for (int i = 0; i < 10; i++) + { + var button = (AppBarButton)(cmdBar.PrimaryCommands.GetAt(i)); + VERIFY_IS_TRUE(button.IsInOverflow); + } + break; + } + case DynamicOverflowOrderTest.OrderTestForTwoPairedValue: // Test for paired order group - {1,2,3,4,5,1,2,3,4,5} + { + VERIFY_IS_TRUE(primaryItemsCount == 4); + VERIFY_IS_TRUE(secondaryCount == 6); + + var button1 = (AppBarButton)(cmdBar.PrimaryCommands.GetAt(0)); + var button8 = (AppBarButton)(cmdBar.PrimaryCommands.GetAt(7)); + VERIFY_IS_TRUE(button1.IsInOverflow); + VERIFY_IS_TRUE(button1.IsInOverflow); + break; + } + case DynamicOverflowOrderTest.OrderTestForFallbackDefault: // Test for order set and default rightmost dynamic overflow - {1,1,2,2,0,0,0,0,0,0} + { + VERIFY_IS_TRUE(primaryItemsCount == 5); + VERIFY_IS_TRUE(secondaryCount == 5); + + var button = (AppBarButton)(cmdBar.PrimaryCommands.GetAt(0)); + VERIFY_IS_TRUE(button.IsInOverflow); + button = (AppBarButton)(cmdBar.PrimaryCommands.GetAt(1)); + VERIFY_IS_TRUE(button.IsInOverflow); + button = (AppBarButton)(cmdBar.PrimaryCommands.GetAt(2)); + VERIFY_IS_TRUE(button.IsInOverflow); + button = (AppBarButton)(cmdBar.PrimaryCommands.GetAt(3)); + VERIFY_IS_TRUE(button.IsInOverflow); + button = (AppBarButton)(cmdBar.PrimaryCommands.GetAt(9)); + VERIFY_IS_TRUE(button.IsInOverflow); + break; + } + case DynamicOverflowOrderTest.OrderTestForMovingPriorSeparator: // Test for order set with moving the separator together - {|, 1, |, 2, 3, 4, 5, 1, 2, 3, 4, 5} + { + var separator = (AppBarSeparator)(cmdBar.PrimaryCommands.GetAt(0)); + VERIFY_IS_FALSE(separator.IsInOverflow); + var button = (AppBarButton)(cmdBar.PrimaryCommands.GetAt(1)); + VERIFY_IS_TRUE(button.IsInOverflow); + separator = (AppBarSeparator)(cmdBar.PrimaryCommands.GetAt(2)); + VERIFY_IS_FALSE(separator.IsInOverflow); + break; + } + case DynamicOverflowOrderTest.OrderTestForMovingPosteriorSeparator: // Test for order set and default rightmost dynamic overflow with moving the separator together - {0, 0, 0, 0, 0, 0, 0, 0, 0, |, 1, |} + { + var separator = (AppBarSeparator)(cmdBar.PrimaryCommands.GetAt(9)); + VERIFY_IS_FALSE(separator.IsInOverflow); + var button = (AppBarButton)(cmdBar.PrimaryCommands.GetAt(10)); + VERIFY_IS_TRUE(button.IsInOverflow); + separator = (AppBarSeparator)(cmdBar.PrimaryCommands.GetAt(11)); + VERIFY_IS_FALSE(separator.IsInOverflow); + break; + } + } + }); + await WindowHelper.WaitForIdle(); + + await CloseCommandBar(cmdBar); + } + + private CommandBar CreateCommandBarWithPrimaryCommandOrderSet(DynamicOverflowOrderTest orderTestCase) + { + AppBarButton button = null; + + var cmdBar = new CommandBar(); + cmdBar.HorizontalAlignment = HorizontalAlignment.Center; + cmdBar.Width = 400; + + for (int i = 0; i < 10; i++) + { + button = new AppBarButton(); + button.Label = $"p_btn{(i + 1)}"; + cmdBar.PrimaryCommands.Append(button); + } + + switch (orderTestCase) + { + case DynamicOverflowOrderTest.OrderTestForAlternativeValue: // Test for alternative order - {1,2,1,2,1,2,1,2,1,2} + for (int i = 0; i < 10; i++) + { + button = (AppBarButton)(cmdBar.PrimaryCommands.GetAt(i)); + button.DynamicOverflowOrder = i % 2 == 0 ? 1 : 2; + } + break; + case DynamicOverflowOrderTest.OrderTestForAllSameValue: // Test for all same order - {1,1,1,1,1,1,1,1,1,1} + + for (int i = 0; i < 10; i++) + { + button = (AppBarButton)(cmdBar.PrimaryCommands.GetAt(i)); + button.DynamicOverflowOrder = 1; + } + break; + + case DynamicOverflowOrderTest.OrderTestForTwoPairedValue: // Test for paired order group - {1,2,3,4,5,1,2,3,4,5} + + for (int i = 0; i < 10; i++) + { + button = (AppBarButton)(cmdBar.PrimaryCommands.GetAt(i)); + button.DynamicOverflowOrder = i % 5 + 1; + } + break; + + case DynamicOverflowOrderTest.OrderTestForFallbackDefault: // Test for order set and default rightmost dynamic overflow - {1,1,2,2,0,0,0,0,0,0} + + for (int i = 0; i < 10; i++) + { + button = (AppBarButton)(cmdBar.PrimaryCommands.GetAt(i)); + if (i < 2) + { + button.DynamicOverflowOrder = 1; + } + else if (i < 4) + { + button.DynamicOverflowOrder = 2; + } + } + break; + + case DynamicOverflowOrderTest.OrderTestForMovingPriorSeparator: // Test for separator moving that is in the prior index of moving primary command + + for (int i = 0; i < 10; i++) + { + button = (AppBarButton)(cmdBar.PrimaryCommands.GetAt(i)); + button.DynamicOverflowOrder = i % 5 + 1; + } + var separator1 = new AppBarSeparator(); + cmdBar.PrimaryCommands.Insert(1, separator1); + var separator2 = new AppBarSeparator(); + cmdBar.PrimaryCommands.Insert(0, separator2); + break; + + case DynamicOverflowOrderTest.OrderTestForMovingPosteriorSeparator: // Test for separator moving that is in the posterior index of moving primary command + + button = (AppBarButton)(cmdBar.PrimaryCommands.GetAt(9)); + button.DynamicOverflowOrder = 1; + var separatorOne = new AppBarSeparator(); + cmdBar.PrimaryCommands.Insert(10, separatorOne); + var separatorTwo = new AppBarSeparator(); + cmdBar.PrimaryCommands.Insert(9, separatorTwo); + break; + } + + return cmdBar; + } + + private async Task ValidateDynamicOverflowItemsChangingEventWorker(CommandBar cmdBar, bool isAdding) + { + var dynamicOverflowItemsChangingEvent = new Event(); + var dynamicOverflowItemsChangingRegistration = CreateSafeEventRegistration>("DynamicOverflowItemsChanging"); + + using var _ = dynamicOverflowItemsChangingRegistration.Attach(cmdBar, (s, e) => + { + if (e.Action == CommandBarDynamicOverflowAction.AddingToOverflow) + { + VERIFY_IS_TRUE(isAdding); + } + else + { + VERIFY_IS_FALSE(isAdding); + } + dynamicOverflowItemsChangingEvent.Set(); + }); + + await RunOnUIThread(() => + { + if (isAdding) + { + var addedButton1 = new AppBarButton(); + cmdBar.PrimaryCommands.Append(addedButton1); + } + else + { + cmdBar.PrimaryCommands.RemoveAt(0); + } + }); + await dynamicOverflowItemsChangingEvent.WaitForDefault(); + await WindowHelper.WaitForIdle(); + + } + + private async Task<(Page, CommandBar)> SetupDynamicOverflowTest( + int numButtonsToAddExtraToPrimary, + int numButtonsToAddToSecondary, + bool isSetOrder = false) + { + Page page = null; + CommandBar cmdBar = null; + + await RunOnUIThread(() => + { + cmdBar = new CommandBar(); + + + page = WindowHelper.SetupSimulatedAppPage(); + //page.BottomAppBar = cmdBar; + SetPageContent(cmdBar, page); + + var button = new AppBarButton(); + cmdBar.PrimaryCommands.Append(button); + }); + await WindowHelper.WaitForIdle(); + + await RunOnUIThread(async () => + { + var button = (AppBarButton)cmdBar.PrimaryCommands.GetAt(0); + button.Label = "p_btn0"; + + var moreButton = await GetMoreButton(cmdBar); + + LOG_OUTPUT($"CommandBar ActualWidth = {cmdBar.ActualWidth}"); + LOG_OUTPUT($"AppBarButton ActualWidth = {button.ActualWidth}"); + LOG_OUTPUT($"MoreButton ActualWidth = {moreButton.ActualWidth}"); + + VERIFY_ARE_NOT_EQUAL(button.ActualWidth, 0); + + int numButtonsToStayOnPrimary = (int)((cmdBar.ActualWidth - moreButton.ActualWidth) / button.ActualWidth); + int numButtonsToAddToPrimary = numButtonsToStayOnPrimary + numButtonsToAddExtraToPrimary - 1; + + for (int i = 0; i < numButtonsToAddToPrimary; ++i) + { + button = new AppBarButton(); + button.Label = $"p_btn{(i + 1)}"; + if (isSetOrder) + { + button.DynamicOverflowOrder = i; + } + cmdBar.PrimaryCommands.Append(button); + } + + for (int i = 0; i < numButtonsToAddToSecondary; ++i) + { + button = new AppBarButton(); + button.Label = $"s_btn{i}"; + cmdBar.SecondaryCommands.Append(button); + } + }); + await WindowHelper.WaitForIdle(); + + return (page, cmdBar); + } + + private async Task ValidateOverflowButtonHidesWhenAppropriate(bool addPrimary, bool addSecondary) + { + TestCleanupWrapper cleanup; + + for (int closedDisplayModeValue = 0; closedDisplayModeValue < 3; closedDisplayModeValue++) + { + for (int defaultLabelPositionValue = 0; defaultLabelPositionValue < 3; defaultLabelPositionValue++) + { + for (int overflowButtonVisibilityValue = 0; overflowButtonVisibilityValue < 3; overflowButtonVisibilityValue++) + { + AppBarClosedDisplayMode closedDisplayMode = (AppBarClosedDisplayMode)closedDisplayModeValue; + CommandBarDefaultLabelPosition defaultLabelPosition = (CommandBarDefaultLabelPosition)defaultLabelPositionValue; + CommandBarOverflowButtonVisibility overflowButtonVisibility = (CommandBarOverflowButtonVisibility)overflowButtonVisibilityValue; + + LOG_OUTPUT($"Testing the overflow button's visibility with {(addPrimary ? "a primary button" : "no primary buttons")}, {(addSecondary ? "a secondary button" : "no secondary buttons")}, ClosedDisplayMode = {(closedDisplayMode == AppBarClosedDisplayMode.Compact ? "Compact" : (closedDisplayMode == AppBarClosedDisplayMode.Minimal ? "Minimal" : "Hidden"))}, DefaultLabelPosition = {(defaultLabelPosition == CommandBarDefaultLabelPosition.Bottom ? "Bottom" : (defaultLabelPosition == CommandBarDefaultLabelPosition.Right ? "Right" : "Collapsed"))}, and OverflowButtonVisibility = {(overflowButtonVisibility == CommandBarOverflowButtonVisibility.Auto ? "Auto" : (overflowButtonVisibility == CommandBarOverflowButtonVisibility.Visible ? "Visible" : "Collapsed"))}."); + + // We expect the overflow button to be visible if we tell it to be visible through OverflowButtonVisibility, + // or if OverflowButtonVisibility is Auto and either there are secondary items or there is at least one primary item + // with a bottom-aligned label, or if ClosedDisplayMode is something other than Compact. + Visibility expectedOverflowButtonVisibility = + overflowButtonVisibility == CommandBarOverflowButtonVisibility.Visible || + (overflowButtonVisibility == CommandBarOverflowButtonVisibility.Auto && + (addSecondary || + (addPrimary && defaultLabelPosition == CommandBarDefaultLabelPosition.Bottom) || + closedDisplayMode != AppBarClosedDisplayMode.Compact)) ? + Visibility.Visible : + Visibility.Collapsed; + + LOG_OUTPUT($"We expect the overflow button to be {(expectedOverflowButtonVisibility == Visibility.Visible ? "visible" : "collapsed")}."); + + await ValidateOverflowButtonState( + addPrimary, + addSecondary, + closedDisplayMode, + defaultLabelPosition, + overflowButtonVisibility, + expectedOverflowButtonVisibility); + } + } + } + } + + private async Task ValidateDynamicOverflowWorker( + CommandBar cmdBar, + bool isPrimaryCommandMovedToOverflow, + int numButtonsToAddExtraToPrimary, + int numButtonsToAddToSecondary, + bool isSetOrder = false) + { + int primaryItemsCount = 0; + + await RunOnUIThread(async () => + { + var primaryItemsControl = (ItemsControl)TreeHelper.GetVisualChildByName(cmdBar, "PrimaryItemsControl"); + var primaryItems = primaryItemsControl.Items; + + primaryItemsCount = primaryItems.Count; + + LOG_OUTPUT($"Number of buttons in CommandBar.PrimaryCommands: {cmdBar.PrimaryCommands.Count}"); + LOG_OUTPUT($"Number of buttons in CommandBar.SecondaryCommands: {cmdBar.SecondaryCommands.Count}"); + LOG_OUTPUT($"Number of buttons in CommandBar.PrimaryItemsControl Count: {primaryItemsCount}"); + LOG_OUTPUT($"PrimaryItemsControl ActualWidth = {primaryItemsControl.ActualWidth}"); + + if (isPrimaryCommandMovedToOverflow) + { + var button = (AppBarButton)cmdBar.PrimaryCommands.GetAt(0); + var moreButton = await GetMoreButton(cmdBar); + int numButtonsToStayOnPrimary = (int)((cmdBar.ActualWidth - moreButton.ActualWidth) / button.ActualWidth); + + VERIFY_IS_TRUE(primaryItemsCount == numButtonsToStayOnPrimary); + VERIFY_IS_TRUE(cmdBar.PrimaryCommands.Count == primaryItemsCount + numButtonsToAddExtraToPrimary); + } + else + { + VERIFY_IS_TRUE(cmdBar.PrimaryCommands.Count == primaryItemsCount); + } + + bool areAllPrimaryItemsCompact = true; + for (int i = 0; i < primaryItems.Count; i++) + { + var button = (AppBarButton)primaryItems.GetAt(i); + areAllPrimaryItemsCompact = areAllPrimaryItemsCompact && button.IsCompact; + } + VERIFY_IS_TRUE(areAllPrimaryItemsCompact); + }); + + await OpenCommandBar(cmdBar, OpenMethod.Programmatic); + + await RunOnUIThread(async () => + { + int numButtonsPrimaryCommandsInOverflow = cmdBar.PrimaryCommands.Count - primaryItemsCount; + + var overflowContentRoot = (FrameworkElement)TreeHelper.GetVisualChildByNameFromOpenPopups("OverflowContentRoot", cmdBar); + var secondaryItemsControl = (ItemsControl)TreeHelper.GetVisualChildByName(overflowContentRoot, "SecondaryItemsControl"); + var secondaryItems = secondaryItemsControl.Items; + + LOG_OUTPUT($"Number of primary buttons in current Primary items : {primaryItemsCount}"); + LOG_OUTPUT($"Number of buttons in current SecondaryCommands items : {secondaryItems.Size}"); + LOG_OUTPUT($"Number of primary buttons in overflow: {numButtonsPrimaryCommandsInOverflow}"); + + VERIFY_IS_TRUE(isPrimaryCommandMovedToOverflow ? numButtonsPrimaryCommandsInOverflow == numButtonsToAddExtraToPrimary : numButtonsPrimaryCommandsInOverflow == 0); + VERIFY_IS_TRUE(secondaryItems.Count == numButtonsPrimaryCommandsInOverflow + numButtonsToAddToSecondary + (isPrimaryCommandMovedToOverflow ? 1 : 0)); + + for (int i = 0; i < secondaryItems.Count; i++) + { + if (i < numButtonsPrimaryCommandsInOverflow) + { + var button = (AppBarButton)(secondaryItems.GetAt(i)); + VERIFY_IS_TRUE(await ControlHelper.IsInVisualState(button, "ApplicationViewStates", "Overflow")); + } + else if (isPrimaryCommandMovedToOverflow && i == numButtonsPrimaryCommandsInOverflow) + { + var overflowSeparator = (AppBarSeparator)(secondaryItems.GetAt(i)); + VERIFY_IS_TRUE(await ControlHelper.IsInVisualState(overflowSeparator, "ApplicationViewStates", "Overflow")); + } + else + { + var button = (AppBarButton)(secondaryItems.GetAt(i)); + VERIFY_IS_TRUE(await ControlHelper.IsInVisualState(button, "ApplicationViewStates", "Overflow")); + } + } + + if (isSetOrder) + { + int maxOrderInOverflow = 0; + + for (int i = 0; i < numButtonsPrimaryCommandsInOverflow; i++) + { + var button = (AppBarButton)(secondaryItems.GetAt(i)); + if (button.DynamicOverflowOrder > maxOrderInOverflow) + { + maxOrderInOverflow = button.DynamicOverflowOrder; + } + } + + var primaryItemsControl = (ItemsControl)(TreeHelper.GetVisualChildByName(cmdBar, "PrimaryItemsControl")); + var primaryItems = primaryItemsControl.Items; + + for (int i = 0; i < primaryItems.Count; i++) + { + var button = (AppBarButton)(primaryItems.GetAt(i)); + if (button.DynamicOverflowOrder != 0) + { + VERIFY_IS_TRUE(button.DynamicOverflowOrder > maxOrderInOverflow); + } + } + } + + }); + + await CloseCommandBar(cmdBar); + } + + private async Task ValidateOverflowButtonState( + bool addPrimary, + bool addSecondary, + AppBarClosedDisplayMode closedDisplayMode, + CommandBarDefaultLabelPosition defaultLabelPosition, + CommandBarOverflowButtonVisibility overflowButtonVisibility, + Visibility expectedOverflowButtonVisibility) + { + CommandBar cmdBar = null; + + var loadedEvent = new Event(); + var loadedRegistration = CreateSafeEventRegistration("Loaded"); + + await RunOnUIThread(() => + { + var rootGrid = new Grid(); + + loadedRegistration.Attach(rootGrid, (s, e) => loadedEvent.Set()); + + cmdBar = new CommandBar(); + cmdBar.ClosedDisplayMode = closedDisplayMode; + cmdBar.DefaultLabelPosition = defaultLabelPosition; + cmdBar.OverflowButtonVisibility = overflowButtonVisibility; + + if (addPrimary) + { + var button = new AppBarButton(); + button.Label = "button"; + cmdBar.PrimaryCommands.Append(button); + } + + if (addSecondary) + { + var button = new AppBarButton(); + button.Label = "button"; + cmdBar.SecondaryCommands.Append(button); + } + + rootGrid.Children.Append(cmdBar); + SetWindowContent(rootGrid); + }); + + await loadedEvent.WaitForDefault(); + await WindowHelper.WaitForIdle(); + + await RunOnUIThread(() => + { + VERIFY_ARE_EQUAL(TreeHelper.GetVisualChildByName(cmdBar, "MoreButton").Visibility, expectedOverflowButtonVisibility); + }); + } + + private async Task OpenCommandBar(CommandBar cmdBar, OpenMethod openMethod) + { + Event openedEvent = new Event(); + var openedRegistration = CreateSafeEventRegistration>("Opened"); + openedRegistration.Attach(cmdBar, (s, e) => openedEvent.Set()); + Control moreButton = await GetMoreButton(cmdBar); + + if (openMethod == OpenMethod.Mouse) + { + ControlHelper.DoClickUsingAP(moreButton as Button); + } + else if (openMethod == OpenMethod.Touch) + { + ControlHelper.DoClickUsingAP(moreButton as Button); + } + else if (openMethod == OpenMethod.Keyboard) + { + await RunOnUIThread(() => moreButton.Focus(FocusState.Keyboard)); + await WindowHelper.WaitForIdle(); + KeyboardHelper.PressKeySequence(" ", moreButton); + } + else if (openMethod == OpenMethod.Gamepad) + { + await RunOnUIThread(() => moreButton.Focus(FocusState.Keyboard)); + await WindowHelper.WaitForIdle(); + CommonInputHelper.Accept(InputDevice.Gamepad, moreButton); + } + else if (openMethod == OpenMethod.Programmatic) + { + await RunOnUIThread(() => cmdBar.IsOpen = true); + + } + + await openedEvent.WaitForDefault(); + await WindowHelper.WaitForIdle(); + await Task.Delay(2000); + } + + private async Task CloseCommandBar(CommandBar cmdBar) + { + var closedEvent = new Event(); + var closedRegistration = CreateSafeEventRegistration>("Closed"); + closedRegistration.Attach(cmdBar, (s, e) => closedEvent.Set()); + + await RunOnUIThread(() => cmdBar.IsOpen = false); + await closedEvent.WaitForDefault(); + await WindowHelper.WaitForIdle(); + } + + private async Task EmptyPageContent(Page page) + { + await RunOnUIThread(() => + { + page.TopAppBar = null; + page.BottomAppBar = null; + page.Content = null; + }); + await WindowHelper.WaitForIdle(); + } + + private async Task SimulateTabAsync(UIElement container) => await SimulateNavigationDirectionAsync(container, FocusNavigationDirection.Next); + + private async Task SimulateShiftTabAsync(UIElement container) => await SimulateNavigationDirectionAsync(container, FocusNavigationDirection.Previous); + + private async Task SimulateUpAsync(UIElement container) => await SimulateNavigationDirectionAsync(container, FocusNavigationDirection.Up); + + private async Task SimulateNavigationDirectionAsync(UIElement container, FocusNavigationDirection direction) + { + await RunOnUIThread(() => + { + var nextElement = FocusManager.FindNextElement(direction, new FindNextElementOptions() + { +#if !WINDOWS_UWP + SearchRoot = container.XamlRoot.Content +#endif + }); + if (nextElement != null && nextElement is UIElement uiElement) + { + uiElement.Focus(FocusState.Keyboard); + } + }); + // Small delay to ensure the focus event have time to fire + await Task.Delay(50); + } + + + private static UIElement GetSecondaryItemsPresenter(CommandBar cmdBar) + { + UIElement secondaryItemsPresenter; + var commandBarOverflowPresenter = TreeHelper.GetVisualChildByNameFromOpenPopups("SecondaryItemsControl", cmdBar); + secondaryItemsPresenter = TreeHelper.GetVisualChildByName(commandBarOverflowPresenter, "ItemsPresenter"); + return secondaryItemsPresenter; + } + + + private async Task ValidateUIElementTestSetup(bool addPrimary, bool addSecondary) + { + // xaml_controls::Grid^ rootGrid = nullptr; + // RunOnUIThread([&] () + + //{ + // rootGrid = ref new xaml_controls::Grid(); + // TestServices::WindowHelper->WindowContent = rootGrid; + //}); + // TestServices::WindowHelper->WaitForIdle(); + + //// Inject a tab to ensure that the last input device type used is consistent, + //// since that affects the layout of the CommandBar. + //TestServices::KeyboardHelper->Tab(); + + //xaml_controls::AppBarButton^ lastAddedButton = nullptr; + + // RunOnUIThread([&] () + + //{ + // const size_t numClosedDisplayModes = 3; + // const size_t numDefaultLabelPositions = 3; + + // for (size_t mode = 0; mode < numClosedDisplayModes; ++mode) + // { + // for (size_t isOpen = 0; isOpen < 2; ++isOpen) + // { + // for (size_t defaultLabelPosition = 0; defaultLabelPosition < numDefaultLabelPositions; ++defaultLabelPosition) + // { + // auto cmdBar = ref new xaml_controls::CommandBar(); + // cmdBar->IsOpen = (isOpen > 0); + // cmdBar->ClosedDisplayMode = static_cast(mode); + // cmdBar->DefaultLabelPosition = static_cast(defaultLabelPosition); + + // if (addPrimary) + // { + // lastAddedButton = ref new xaml_controls::AppBarButton(); + // lastAddedButton->Label = "button"; + // cmdBar->PrimaryCommands->Append(lastAddedButton); + // } + + // if (addSecondary) + // { + // lastAddedButton = ref new xaml_controls::AppBarButton(); + // lastAddedButton->Label = "button"; + // cmdBar->SecondaryCommands->Append(lastAddedButton); + // } + + // rootGrid->Children->Append(cmdBar); + // xaml_controls::Grid::SetRow(cmdBar, 2 * static_cast(mode) + static_cast(isOpen)); + // xaml_controls::Grid::SetColumn(cmdBar, static_cast(defaultLabelPosition)); + // } + // } + // } + + // for (size_t rowCount = 0; rowCount < 2 * numClosedDisplayModes; rowCount++) + // { + // rootGrid->RowDefinitions->Append(ref new xaml_controls::RowDefinition()); + // } + + // for (size_t columnCount = 0; columnCount < numDefaultLabelPositions; columnCount++) + // { + // rootGrid->ColumnDefinitions->Append(ref new xaml_controls::ColumnDefinition()); + // } + //}); + // TestServices::WindowHelper->WaitForIdle(); + + //// Set focus on a primary button or a secondary button because having focus present on the MoreButton (by default) + //// causes the "See More" ToolTip to appear depending upon timing and cause unpredictable failures. + //RunOnUIThread([&] () + + //{ + // lastAddedButton->Focus(xaml::FocusState::Programmatic); + //}); + // TestServices::WindowHelper->WaitForIdle(); + + // return rootGrid; + return new Grid(); + } + + private async Task ValidateRightClickBehaviorWorker(AppBarClosedDisplayMode closedDisplayMode) + { + // // CoreWindow isn't agile, so we can't use the SafeEventRegistration utility, + // // so we have to manage it manually. + // wf::EventRegistrationToken coreWindowPointerPressedToken = { }; + + // TestCleanupWrapper cleanup([&coreWindowPointerPressedToken]() + + //{ + // RunOnUIThread([&coreWindowPointerPressedToken]() + + // { + // xaml::Window::Current->CoreWindow->PointerPressed -= coreWindowPointerPressedToken; + // coreWindowPointerPressedToken = { }; + // }); + + // TestServices::WindowHelper->ResetWindowContentAndWaitForIdle(); + // }); + + // // CommandBars should never open in response to right-click. + // const bool expectedTopBottomIsOpenValue = false; + // const bool expectedInlineIsOpenValue = false; + + // xaml_controls::Page ^ page = nullptr; + // xaml_controls::CommandBar ^ topCmdBar = nullptr; + // xaml_controls::CommandBar ^ bottomCmdBar = nullptr; + // xaml_controls::CommandBar ^ inlineCmdBar = nullptr; + + // auto rightClickProcessedEvent = std::make_shared(); + + // RunOnUIThread([&]() + + //{ + // topCmdBar = ref new xaml_controls::CommandBar(); + // bottomCmdBar = ref new xaml_controls::CommandBar(); + // inlineCmdBar = ref new xaml_controls::CommandBar(); + + // topCmdBar->ClosedDisplayMode = closedDisplayMode; + // bottomCmdBar->ClosedDisplayMode = closedDisplayMode; + // inlineCmdBar->ClosedDisplayMode = closedDisplayMode; + + // auto grid = ref new xaml_controls::Grid(); + // grid->Children->Append(inlineCmdBar); + + // coreWindowPointerPressedToken = xaml::Window::Current->CoreWindow->PointerPressed += + // ref new wf::TypedEventHandler ([rightClickProcessedEvent](wuc::CoreWindow ^, wuc::PointerEventArgs ^) { + // rightClickProcessedEvent->Set(); + // }); + + // page = TestServices::WindowHelper->SetupSimulatedAppPage(); + // auto frame = safe_cast < xaml_controls::Frame ^> (Window::Current->Content); + + // page->TopAppBar = topCmdBar; + // page->BottomAppBar = bottomCmdBar; + // page->Content = grid; + // }); + // TestServices::WindowHelper->WaitForIdle(); + + // // Inject right-click. + // TestServices::InputHelper->MoveMouse(page); + // TestServices::InputHelper->MouseButtonDown(page, 0, 0, MouseButton::Right); + // TestServices::InputHelper->MouseButtonUp(page, 0, 0, MouseButton::Right); + // TestServices::WindowHelper->WaitForIdle(); + // rightClickProcessedEvent->WaitForDefault(); + + // RunOnUIThread([&]() + + //{ + // VERIFY_ARE_EQUAL(topCmdBar->IsOpen, expectedTopBottomIsOpenValue); + // VERIFY_ARE_EQUAL(bottomCmdBar->IsOpen, expectedTopBottomIsOpenValue); + // VERIFY_ARE_EQUAL(inlineCmdBar->IsOpen, expectedInlineIsOpenValue); + // }); + // TestServices::WindowHelper->WaitForIdle(); + + // EmptyPageContent(page); + } + + private async Task ValidateOverflowPlacementWorker(OverflowOpenDirection openDirection, OverflowAlignment alignment, bool isRTL) + { + var loadedEvent = new Event(); + var loadedRegistration = CreateSafeEventRegistration("Loaded"); + + CommandBar cmdBar = null; + Grid root = null; + + await RunOnUIThread(() => + { + cmdBar = new CommandBar(); + cmdBar.Width = 150; + var menuitem = new AppBarButton(); + menuitem.Label = "menu item"; + menuitem.Width = 200; + cmdBar.SecondaryCommands.Append(menuitem); + + cmdBar.VerticalAlignment = openDirection == OverflowOpenDirection.Up ? VerticalAlignment.Bottom : VerticalAlignment.Top; + cmdBar.HorizontalAlignment = alignment == OverflowAlignment.Left ? HorizontalAlignment.Left : HorizontalAlignment.Right; + + root = new Grid(); + root.Children.Append(cmdBar); + if (isRTL) + { + root.FlowDirection = FlowDirection.RightToLeft; + } + + loadedRegistration.Attach(root, (s, e) => + { + LOG_OUTPUT("Grid.Loaded raised."); + loadedEvent.Set(); + }); + + SetWindowContent(root); + }); + + await loadedEvent.WaitForDefault(); + await WindowHelper.WaitForIdle(); + + //UNO TODO: IsOpen on load + await RunOnUIThread(() => cmdBar.IsOpen = true); + await Task.Delay(2000); + + await RunOnUIThread(() => + { + var overflowContentRoot = (UIElement)TreeHelper.GetVisualChildByNameFromOpenPopups("OverflowContentRoot", cmdBar); + VERIFY_IS_NOT_NULL(overflowContentRoot); + + var transform = overflowContentRoot.TransformToVisual(cmdBar); + var overflowTransformedBounds = transform.TransformBounds(new Rect(0, 0, overflowContentRoot.DesiredSize.Width, overflowContentRoot.DesiredSize.Height)); + + if (openDirection == OverflowOpenDirection.Up) + { + VERIFY_IS_LESS_THAN(overflowTransformedBounds.Y, 0); + } + else // OverflowOpenDirection::Down + { + VERIFY_IS_GREATER_THAN(overflowTransformedBounds.Y, 0); + } + + if (alignment == OverflowAlignment.Left) + { + VERIFY_ARE_VERY_CLOSE(overflowTransformedBounds.X, 0); + } + else // OverflowAlignment::Right + { + VERIFY_ARE_VERY_CLOSE(cmdBar.ActualWidth, overflowTransformedBounds.X + overflowTransformedBounds.Width); + } + }); + await WindowHelper.WaitForIdle(); + } + + private async Task GetMoreButton(CommandBar cmdBar) + { + Control moreButton = null; + await RunOnUIThread(() => + { + moreButton = (Control)TreeHelper.GetVisualChildByName(cmdBar, "MoreButton"); + }); + + return moreButton; + } + + private async Task ValidateOpenAndCloseWorker(Func openFunc, Func closeFunc) + { + CommandBar cmdBar = null; + + var openedEvent = new Event(); + var closedEvent = new Event(); + + var openedRegistration = CreateSafeEventRegistration>("Opened"); + var closedRegistration = CreateSafeEventRegistration>("Closed"); + + await RunOnUIThread(() => + { + cmdBar = new CommandBar(); + cmdBar.VerticalAlignment = VerticalAlignment.Center; // Center it to get it out from under the status bar. + + // Add at least one primary command and one secondary command to the CommandBar. + cmdBar.PrimaryCommands.Add(new AppBarButton()); + cmdBar.SecondaryCommands.Add(new AppBarButton()); + + openedRegistration.Attach(cmdBar, (s, e) => openedEvent.Set()); + closedRegistration.Attach(cmdBar, (s, e) => closedEvent.Set()); + + var root = new Grid(); + root.Children.Add(cmdBar); + + SetWindowContent(root); + }); + await WindowHelper.WaitForIdle(); + + await openFunc(cmdBar); + await WindowHelper.WaitForIdle(); + await openedEvent.WaitForDefault(); + + await closeFunc(cmdBar); + await WindowHelper.WaitForIdle(); + await closedEvent.WaitForDefault(); + } + + private void SetWindowContent(UIElement content) + { + //SetResources(content); + WindowHelper.WindowContent = content; + } + + private void SetPageContent(UIElement content, Page page) + { + //SetResources(content); + page.Content = content; + } + + private void SetResources(DependencyObject content) + { + var cmdBar = content as CommandBar; + if (cmdBar != null) + { + cmdBar.Resources.MergedDictionaries.Add(new XamlControlsResources()); + return; + } + + foreach (var child in VisualTreeHelper.GetChildren(content)) + { + SetResources(child); + } + } + + private enum Location + { + Inline, + Top, + Bottom + } + + private enum OverflowOpenDirection + { + Up = 0, + Down + } + + private enum OverflowAlignment + { + Left = 0, + Right + } + + private enum OpenMethod + { + Mouse, + Touch, + Keyboard, + Gamepad, + Programmatic + } + + private enum DynamicOverflowOrderTest + { + OrderTestForAlternativeValue, // Test for alternative order - {1,2,1,2,1,2,1,2,1,2} + OrderTestForAllSameValue, // Test for all same order - {1,1,1,1,1,1,1,1,1,1} + OrderTestForTwoPairedValue, // Test for paired order group - {1,2,3,4,5,1,2,3,4,5} + OrderTestForFallbackDefault, // Test for order set and default rightmost dynamic overflow - {1,1,2,2,0,0,0,0,0,0} + OrderTestForMovingPriorSeparator, // Test for separator moving that is in the prior index of moving primary command + OrderTestForMovingPosteriorSeparator // Test for separator moving that is in the posterior index of moving primary command + } + } +} +#endif diff --git a/src/Uno.UI.RuntimeTests/IntegrationTests/dxaml/controls/customtypes/CustomAppBarButton.cs b/src/Uno.UI.RuntimeTests/IntegrationTests/dxaml/controls/customtypes/CustomAppBarButton.cs new file mode 100644 index 000000000000..88e7a566bc55 --- /dev/null +++ b/src/Uno.UI.RuntimeTests/IntegrationTests/dxaml/controls/customtypes/CustomAppBarButton.cs @@ -0,0 +1,29 @@ +#if HAS_UNO +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Windows.UI.Xaml.Controls; + +namespace Windows.UI.Tests.Enterprise.CustomTypes +{ + public partial class CustomAppBarButton : Button, ICommandBarElement + { + private bool m_isCompact; + private int m_dynamicOverflowOrder; + private bool m_IsInOverflow; + + public bool IsCompact { get => m_isCompact; set => m_isCompact = value; } + public int DynamicOverflowOrder { get => m_dynamicOverflowOrder; set => m_dynamicOverflowOrder = value; } + public bool IsInOverflow { get => m_IsInOverflow; } + + public CustomAppBarButton() + { + m_isCompact = false; + m_dynamicOverflowOrder = 0; + m_IsInOverflow = false; + } + } +} +#endif diff --git a/src/Uno.UI.RuntimeTests/MUX/Helpers/CommonInputHelper.cs b/src/Uno.UI.RuntimeTests/MUX/Helpers/CommonInputHelper.cs new file mode 100644 index 000000000000..88d17546a22e --- /dev/null +++ b/src/Uno.UI.RuntimeTests/MUX/Helpers/CommonInputHelper.cs @@ -0,0 +1,115 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Windows.UI.Xaml; +using static Private.Infrastructure.TestServices; + +namespace Uno.UI.RuntimeTests.MUX.Helpers +{ + internal enum InputDevice + { + Keyboard, + Gamepad, + } + + internal class CommonInputHelper + { + internal static void Cancel(InputDevice device, UIElement element = null) + { + switch(device) + { + case InputDevice.Keyboard: + KeyboardHelper.Escape(element); + break; + + case InputDevice.Gamepad: + KeyboardHelper.GamepadB(element); + break; + default: + throw new Exception("Invalid input device."); + } + } + + internal static void Accept(InputDevice device, UIElement element = null) + { + switch (device) + { + case InputDevice.Keyboard: + KeyboardHelper.Space(element); + break; + + case InputDevice.Gamepad: + KeyboardHelper.GamepadA(element); + break; + default: + throw new Exception("Invalid input device."); + } + } + + internal static void Right(InputDevice device, UIElement element = null) + { + switch (device) + { + case InputDevice.Keyboard: + KeyboardHelper.Right(element); + break; + + case InputDevice.Gamepad: + KeyboardHelper.GamepadDpadRight(element); + break; + default: + throw new Exception("Invalid input device."); + } + } + + internal static void Left(InputDevice device, UIElement element = null) + { + switch (device) + { + case InputDevice.Keyboard: + KeyboardHelper.Left(element); + break; + + case InputDevice.Gamepad: + KeyboardHelper.GamepadDpadLeft(element); + break; + default: + throw new Exception("Invalid input device."); + } + } + + internal static void Up(InputDevice device, UIElement element = null) + { + switch (device) + { + case InputDevice.Keyboard: + KeyboardHelper.Up(element); + break; + + case InputDevice.Gamepad: + KeyboardHelper.GamepadDpadUp(element); + break; + default: + throw new Exception("Invalid input device."); + } + } + + internal static void Down(InputDevice device, UIElement element = null) + { + switch (device) + { + case InputDevice.Keyboard: + KeyboardHelper.Down(element); + break; + + case InputDevice.Gamepad: + KeyboardHelper.GamepadDpadDown(element); + break; + default: + throw new Exception("Invalid input device."); + } + } + } +} diff --git a/src/Uno.UI.RuntimeTests/MUX/Helpers/ControlHelper.cs b/src/Uno.UI.RuntimeTests/MUX/Helpers/ControlHelper.cs index c7c33f5316d0..76f5dfe15504 100644 --- a/src/Uno.UI.RuntimeTests/MUX/Helpers/ControlHelper.cs +++ b/src/Uno.UI.RuntimeTests/MUX/Helpers/ControlHelper.cs @@ -8,6 +8,9 @@ using MUXControlsTestApp.Utilities; using Uno.Disposables; using Windows.UI.Xaml.Automation.Peers; +using Windows.UI.Xaml.Media; +using System.Collections.Generic; +using Uno.Extensions; namespace Uno.UI.RuntimeTests.MUX.Helpers { @@ -99,5 +102,69 @@ public static async Task ValidateUIElementTree( { throw new NotImplementedException(); } + + public static async Task GetBounds(FrameworkElement element) + { + var rect = new Rect(); + await RunOnUIThread.ExecuteAsync(() => + { + var point1 = element.TransformToVisual(null).TransformPoint(new Point(0, 0)); + var point2 = element.TransformToVisual(null).TransformPoint(new Point(element.ActualWidth, element.ActualHeight)); + + rect.X = Math.Min(point1.X, point2.X); + rect.Y = Math.Min(point1.Y, point2.Y); + rect.Width = Math.Abs(point1.X - point2.X); + rect.Height = Math.Abs(point1.Y - point2.Y); + }); + + return rect; + } + + public static async Task IsInVisualState(Control control, string visualStateGroupName, string visualStateName) + { + bool result = false; + await RunOnUIThread.ExecuteAsync(() => + { + var rootVisual = (FrameworkElement)VisualTreeHelper.GetChild(control, 0); + var visualStateGroup = GetVisualStateGroup(rootVisual, visualStateGroupName); + result = visualStateGroup != null && visualStateName == visualStateGroup.CurrentState.Name; + }); + return result; + } + + public static void RemoveItem(IList items, T item) + { + var index = items.Safe().IndexOf(item); + if (index == -1) + { + throw new ArgumentOutOfRangeException("The item was not in the collection."); + } + items.RemoveAt(index); + } + + private static VisualStateGroup GetVisualStateGroup(FrameworkElement control, string groupName) + { + VisualStateGroup group = null; + var visualStateGroups = VisualStateManager.GetVisualStateGroups(control); + if (visualStateGroups == null && control is ContentControl contentControl) + { + visualStateGroups = VisualStateManager.GetVisualStateGroups(contentControl); + } + + if (visualStateGroups == null) + { + return group; + } + + foreach (var visualStateGroup in visualStateGroups) + { + if (visualStateGroup.Name == groupName) + { + group = visualStateGroup; + return group; + } + } + return group; + } } } diff --git a/src/Uno.UI.RuntimeTests/MUX/Helpers/FlyoutHelper.cs b/src/Uno.UI.RuntimeTests/MUX/Helpers/FlyoutHelper.cs index 3a83fc87a71a..ed7d1859c9b1 100644 --- a/src/Uno.UI.RuntimeTests/MUX/Helpers/FlyoutHelper.cs +++ b/src/Uno.UI.RuntimeTests/MUX/Helpers/FlyoutHelper.cs @@ -1,4 +1,7 @@ using System; +using System.Threading.Tasks; +using MUXControlsTestApp.Utilities; +using Windows.UI; using Windows.UI.Xaml; using Windows.UI.Xaml.Controls; using Windows.UI.Xaml.Controls.Primitives; @@ -47,6 +50,29 @@ public static void ValidateOpenFlyoutOverlayBrush(string name) { throw new NotImplementedException(); } + + public static async Task CreateTarget( + double width, + double height, + Thickness margin, + HorizontalAlignment halign, + VerticalAlignment valign) + { + Border target = null; + + await RunOnUIThread.ExecuteAsync(() => + { + target = new Border(); + target.Background = new SolidColorBrush(Colors.RoyalBlue); + target.Height = height; + target.Width = width; + target.Margin = margin; + target.HorizontalAlignment = halign; + target.VerticalAlignment = valign; + }); + + return target; + } } internal enum FlyoutOpenMethod diff --git a/src/Uno.UI.RuntimeTests/MUX/Microsoft_UI_Xaml_Controls/Repeater/FlowLayoutCollectionChangeTests.cs b/src/Uno.UI.RuntimeTests/MUX/Microsoft_UI_Xaml_Controls/Repeater/FlowLayoutCollectionChangeTests.cs index ffcb041adf9b..5977b0d4b37d 100644 --- a/src/Uno.UI.RuntimeTests/MUX/Microsoft_UI_Xaml_Controls/Repeater/FlowLayoutCollectionChangeTests.cs +++ b/src/Uno.UI.RuntimeTests/MUX/Microsoft_UI_Xaml_Controls/Repeater/FlowLayoutCollectionChangeTests.cs @@ -31,6 +31,7 @@ using ItemsRepeaterScrollHost = Microsoft.UI.Xaml.Controls.ItemsRepeaterScrollHost; using AnimationContext = Microsoft.UI.Xaml.Controls.AnimationContext; using System.Collections.Generic; +using Uno.UI.RuntimeTests; namespace Windows.UI.Xaml.Tests.MUXControls.ApiTests.RepeaterTests { @@ -429,6 +430,9 @@ public void VerifyElement0OwnershipInUniformGridLayout() [TestMethod] #if __WASM__ || __ANDROID__ [Ignore("UNO: ManualResetEvent not supported on WASM for now https://github.com/unoplatform/uno/issues/4529")] +#endif +#if __SKIA__ + [RequiresFullWindow] #endif public void EnsureReplaceOfAnchorDoesNotResetAllContainers() { @@ -501,6 +505,9 @@ public void ValidateStableResets() [TestMethod] #if __WASM__ || __IOS__ || __ANDROID__ [Ignore("UNO: Test does not pass yet with Uno https://github.com/unoplatform/uno/issues/4529")] +#endif +#if __SKIA__ + [RequiresFullWindow] #endif public void ValidateRegularResets() { @@ -525,6 +532,9 @@ public void ValidateRegularResets() [TestMethod] #if __WASM__ [Ignore("UNO: Test does not pass yet with Uno https://github.com/unoplatform/uno/issues/4529")] +#endif +#if __SKIA__ + [RequiresFullWindow] #endif public void ValidateClear() { diff --git a/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml/Given_FrameworkElement_And_Leak.cs b/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml/Given_FrameworkElement_And_Leak.cs index 5e068b5913db..7d9333132eb4 100644 --- a/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml/Given_FrameworkElement_And_Leak.cs +++ b/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml/Given_FrameworkElement_And_Leak.cs @@ -59,6 +59,7 @@ public class Given_FrameworkElement_And_Leak [DataRow(typeof(Canvas), 15)] [DataRow(typeof(AutoSuggestBox), 15)] [DataRow(typeof(AppBar), 15)] + [DataRow(typeof(CommandBar), 15)] [DataRow(typeof(Border), 15)] [DataRow(typeof(ContentControl), 15)] [DataRow(typeof(ContentDialog), 15)] diff --git a/src/Uno.UI.Toolkit/CommandBarExtensions.cs b/src/Uno.UI.Toolkit/CommandBarExtensions.cs index 6c08f499df82..b30d9a148aca 100644 --- a/src/Uno.UI.Toolkit/CommandBarExtensions.cs +++ b/src/Uno.UI.Toolkit/CommandBarExtensions.cs @@ -16,7 +16,7 @@ namespace Uno.UI.Toolkit #endif public static class CommandBarExtensions { - #region Subtitle +#region Subtitle public static DependencyProperty SubtitleProperty { get; } = DependencyProperty.RegisterAttached( @@ -36,9 +36,9 @@ public static string GetSubtitle(this CommandBar commandBar) return (string)commandBar.GetValue(SubtitleProperty); } - #endregion +#endregion - #region NavigationCommand +#region NavigationCommand public static DependencyProperty NavigationCommandProperty { get; } = DependencyProperty.RegisterAttached( @@ -62,9 +62,9 @@ public static AppBarButton GetNavigationCommand(this CommandBar commandBar) return (AppBarButton)commandBar.GetValue(NavigationCommandProperty); } - #endregion +#endregion - #region BackButtonTitle +#region BackButtonTitle public static DependencyProperty BackButtonTitleProperty { get; } = DependencyProperty.RegisterAttached( @@ -84,9 +84,9 @@ public static string GetBackButtonTitle(this CommandBar commandBar) return (string)commandBar.GetValue(BackButtonTitleProperty); } - #endregion +#endregion - #region BackButtonVisibility +#region BackButtonVisibility public static DependencyProperty BackButtonVisibilityProperty { get; } = DependencyProperty.RegisterAttached( @@ -106,9 +106,9 @@ public static Visibility GetBackButtonVisibility(this CommandBar commandBar) return (Visibility)commandBar.GetValue(BackButtonVisibilityProperty); } - #endregion +#endregion - #region BackButtonForeground +#region BackButtonForeground public static DependencyProperty BackButtonForegroundProperty { get; } = DependencyProperty.RegisterAttached( @@ -132,9 +132,9 @@ public static Brush GetBackButtonForeground(this CommandBar commandBar) return (Brush)commandBar.GetValue(BackButtonForegroundProperty); } - #endregion +#endregion - #region BackButtonIcon +#region BackButtonIcon public static DependencyProperty BackButtonIconProperty { get; } = DependencyProperty.RegisterAttached( @@ -154,6 +154,6 @@ public static IconElement GetBackButtonIcon(this CommandBar commandBar) return (IconElement)commandBar.GetValue(BackButtonIconProperty); } - #endregion +#endregion } } diff --git a/src/Uno.UI/Controls/AppBarButtonRenderer.Android.cs b/src/Uno.UI/Controls/CommandBar/AppBarButtonRenderer.Android.cs similarity index 100% rename from src/Uno.UI/Controls/AppBarButtonRenderer.Android.cs rename to src/Uno.UI/Controls/CommandBar/AppBarButtonRenderer.Android.cs diff --git a/src/Uno.UI/Controls/AppBarButtonRenderer.iOS.cs b/src/Uno.UI/Controls/CommandBar/AppBarButtonRenderer.iOS.cs similarity index 100% rename from src/Uno.UI/Controls/AppBarButtonRenderer.iOS.cs rename to src/Uno.UI/Controls/CommandBar/AppBarButtonRenderer.iOS.cs diff --git a/src/Uno.UI/Controls/CommandBarHelper.iOS.cs b/src/Uno.UI/Controls/CommandBar/CommandBarHelper.iOS.cs similarity index 99% rename from src/Uno.UI/Controls/CommandBarHelper.iOS.cs rename to src/Uno.UI/Controls/CommandBar/CommandBarHelper.iOS.cs index f6f27d4e1ccf..8be1c034a6b8 100644 --- a/src/Uno.UI/Controls/CommandBarHelper.iOS.cs +++ b/src/Uno.UI/Controls/CommandBar/CommandBarHelper.iOS.cs @@ -119,4 +119,4 @@ public static void PageWillDisappear(UIViewController pageController) ?? controller.View.FindFirstChild(); } } -} \ No newline at end of file +} diff --git a/src/Uno.UI/Controls/CommandBarNavigationItemRenderer.iOS.cs b/src/Uno.UI/Controls/CommandBar/CommandBarNavigationItemRenderer.iOS.cs similarity index 100% rename from src/Uno.UI/Controls/CommandBarNavigationItemRenderer.iOS.cs rename to src/Uno.UI/Controls/CommandBar/CommandBarNavigationItemRenderer.iOS.cs diff --git a/src/Uno.UI/Controls/CommandBarRenderer.Android.cs b/src/Uno.UI/Controls/CommandBar/CommandBarRenderer.Android.cs similarity index 100% rename from src/Uno.UI/Controls/CommandBarRenderer.Android.cs rename to src/Uno.UI/Controls/CommandBar/CommandBarRenderer.Android.cs diff --git a/src/Uno.UI/Controls/CommandBarRenderer.iOS.cs b/src/Uno.UI/Controls/CommandBar/CommandBarRenderer.iOS.cs similarity index 100% rename from src/Uno.UI/Controls/CommandBarRenderer.iOS.cs rename to src/Uno.UI/Controls/CommandBar/CommandBarRenderer.iOS.cs diff --git a/src/Uno.UI/Controls/NativeCommandBarPresenter.Android.cs b/src/Uno.UI/Controls/CommandBar/NativeCommandBarPresenter.Android.cs similarity index 100% rename from src/Uno.UI/Controls/NativeCommandBarPresenter.Android.cs rename to src/Uno.UI/Controls/CommandBar/NativeCommandBarPresenter.Android.cs diff --git a/src/Uno.UI/Controls/NativeCommandBarPresenter.iOS.cs b/src/Uno.UI/Controls/CommandBar/NativeCommandBarPresenter.iOS.cs similarity index 100% rename from src/Uno.UI/Controls/NativeCommandBarPresenter.iOS.cs rename to src/Uno.UI/Controls/CommandBar/NativeCommandBarPresenter.iOS.cs diff --git a/src/Uno.UI/DirectUI/IterableWrappedCollection.cs b/src/Uno.UI/DirectUI/IterableWrappedCollection.cs new file mode 100644 index 000000000000..f2b2b3399a75 --- /dev/null +++ b/src/Uno.UI/DirectUI/IterableWrappedCollection.cs @@ -0,0 +1,73 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Uno.Disposables; +using Windows.Foundation.Collections; + +namespace DirectUI +{ + internal class IterableWrappedCollection : IVector, IIterable + { + protected IVector m_tpWrappedCollection; + + public virtual void SetWrappedCollection(IVector collection) + { + m_tpWrappedCollection = collection; + } + + public T this[int index] + { + get => GetAt(index); + set => SetAt(index, value); + } + + public int Count => m_tpWrappedCollection.Count; + public bool IsReadOnly => m_tpWrappedCollection.IsReadOnly; + + public void Add(T item) => m_tpWrappedCollection.Add(item); + public void Clear() => m_tpWrappedCollection?.Clear(); + public bool Contains(T item) => m_tpWrappedCollection.Contains(item); + public void CopyTo(T[] array, int arrayIndex) => m_tpWrappedCollection.CopyTo(array, arrayIndex); + public IEnumerator GetEnumerator() => m_tpWrappedCollection.GetEnumerator(); + IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); + public IIterator GetIterator() => new UnoEnumeratorToIteratorAdapter(GetEnumerator()); + public int IndexOf(T item) => m_tpWrappedCollection.IndexOf(item); + public void Insert(int index, T item) => m_tpWrappedCollection.Insert(index, item); + public bool Remove(T item) => m_tpWrappedCollection.Remove(item); + public void RemoveAt(int index) => m_tpWrappedCollection.RemoveAt(index); + private T GetAt(int index) => m_tpWrappedCollection[index]; + private void SetAt(int index, T value) => m_tpWrappedCollection[index] = value; + } + + internal class IterableWrappedObservableCollection : IterableWrappedCollection, IObservableVector + { + public event VectorChangedEventHandler VectorChanged; + private SerialDisposable m_VectorChangedToken = new SerialDisposable(); + + public override void SetWrappedCollection(IVector collection) + { + UnsubscribeFromCurrentCollection(); + + base.SetWrappedCollection(collection); + + if (collection is IObservableVector spAsObservable) + { + spAsObservable.VectorChanged += OnVectorChanged; + m_VectorChangedToken.Disposable = Disposable.Create(() => spAsObservable.VectorChanged -= OnVectorChanged); + } + } + + private void OnVectorChanged(IObservableVector sender, IVectorChangedEventArgs @event) + { + VectorChanged?.Invoke(this, @event); + } + + private void UnsubscribeFromCurrentCollection() + { + m_VectorChangedToken.Disposable = null; + } + } +} diff --git a/src/Uno.UI/Extensions/DependencyObjectExtensions.mux.cs b/src/Uno.UI/Extensions/DependencyObjectExtensions.mux.cs index 591cdf85912c..70ae99e59dc7 100644 --- a/src/Uno.UI/Extensions/DependencyObjectExtensions.mux.cs +++ b/src/Uno.UI/Extensions/DependencyObjectExtensions.mux.cs @@ -39,7 +39,7 @@ internal static Uno.UI.Xaml.Core.CoreServices GetContext(this DependencyObject d internal static bool SetFocusedElement( this DependencyObject sourceElement, // In WinUI this parameter does not exist, as the method is static on DependencyObject - DependencyObject pElementToFocus, + DependencyObject? pElementToFocus, FocusState focusState, bool animateIfBringIntoView, bool isProcessingTab = false, @@ -71,7 +71,7 @@ internal static bool SetFocusedElement( internal static bool SetFocusedElementWithDirection( this DependencyObject sourceElement, // In WinUI this parameter does not exist, as the method is static on DependencyObject - DependencyObject pFocusedElement, + DependencyObject? pFocusedElement, FocusState focusState, bool animateIfBringIntoView, FocusNavigationDirection focusNavigationDirection, diff --git a/src/Uno.UI/FeatureConfiguration.cs b/src/Uno.UI/FeatureConfiguration.cs index 8026f31c7b7c..89ad1cf18118 100644 --- a/src/Uno.UI/FeatureConfiguration.cs +++ b/src/Uno.UI/FeatureConfiguration.cs @@ -352,7 +352,7 @@ public static class Style public static IDictionary UseUWPDefaultStylesOverride { get; } = new Dictionary(); /// - /// This enables native frame navigation on Android and iOS by setting related classes (, + /// This enables native frame navigation on Android and iOS by setting related classes (, /// and ) to use their native styles. /// public static void ConfigureNativeFrameNavigation() diff --git a/src/Uno.UI/Generated/3.0.0.0/Windows.UI.Xaml.Automation.Peers/AppBarAutomationPeer.cs b/src/Uno.UI/Generated/3.0.0.0/Windows.UI.Xaml.Automation.Peers/AppBarAutomationPeer.cs index 408cb31a15dd..d506b18555cf 100644 --- a/src/Uno.UI/Generated/3.0.0.0/Windows.UI.Xaml.Automation.Peers/AppBarAutomationPeer.cs +++ b/src/Uno.UI/Generated/3.0.0.0/Windows.UI.Xaml.Automation.Peers/AppBarAutomationPeer.cs @@ -2,149 +2,35 @@ #pragma warning disable 114 // new keyword hiding namespace Windows.UI.Xaml.Automation.Peers { - #if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__ + #if false || false || false || false || false || false || false [global::Uno.NotImplemented] #endif public partial class AppBarAutomationPeer : global::Windows.UI.Xaml.Automation.Peers.FrameworkElementAutomationPeer,global::Windows.UI.Xaml.Automation.Provider.IToggleProvider,global::Windows.UI.Xaml.Automation.Provider.IExpandCollapseProvider,global::Windows.UI.Xaml.Automation.Provider.IWindowProvider { - #if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__ - [global::Uno.NotImplemented("__ANDROID__", "__IOS__", "NET461", "__WASM__", "__SKIA__", "__NETSTD_REFERENCE__", "__MACOS__")] - public global::Windows.UI.Xaml.Automation.ExpandCollapseState ExpandCollapseState - { - get - { - throw new global::System.NotImplementedException("The member ExpandCollapseState AppBarAutomationPeer.ExpandCollapseState is not implemented in Uno."); - } - } - #endif - #if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__ - [global::Uno.NotImplemented("__ANDROID__", "__IOS__", "NET461", "__WASM__", "__SKIA__", "__NETSTD_REFERENCE__", "__MACOS__")] - public global::Windows.UI.Xaml.Automation.ToggleState ToggleState - { - get - { - throw new global::System.NotImplementedException("The member ToggleState AppBarAutomationPeer.ToggleState is not implemented in Uno."); - } - } - #endif - #if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__ - [global::Uno.NotImplemented("__ANDROID__", "__IOS__", "NET461", "__WASM__", "__SKIA__", "__NETSTD_REFERENCE__", "__MACOS__")] - public global::Windows.UI.Xaml.Automation.WindowInteractionState InteractionState - { - get - { - throw new global::System.NotImplementedException("The member WindowInteractionState AppBarAutomationPeer.InteractionState is not implemented in Uno."); - } - } - #endif - #if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__ - [global::Uno.NotImplemented("__ANDROID__", "__IOS__", "NET461", "__WASM__", "__SKIA__", "__NETSTD_REFERENCE__", "__MACOS__")] - public bool IsModal - { - get - { - throw new global::System.NotImplementedException("The member bool AppBarAutomationPeer.IsModal is not implemented in Uno."); - } - } - #endif - #if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__ - [global::Uno.NotImplemented("__ANDROID__", "__IOS__", "NET461", "__WASM__", "__SKIA__", "__NETSTD_REFERENCE__", "__MACOS__")] - public bool IsTopmost - { - get - { - throw new global::System.NotImplementedException("The member bool AppBarAutomationPeer.IsTopmost is not implemented in Uno."); - } - } - #endif - #if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__ - [global::Uno.NotImplemented("__ANDROID__", "__IOS__", "NET461", "__WASM__", "__SKIA__", "__NETSTD_REFERENCE__", "__MACOS__")] - public bool Maximizable - { - get - { - throw new global::System.NotImplementedException("The member bool AppBarAutomationPeer.Maximizable is not implemented in Uno."); - } - } - #endif - #if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__ - [global::Uno.NotImplemented("__ANDROID__", "__IOS__", "NET461", "__WASM__", "__SKIA__", "__NETSTD_REFERENCE__", "__MACOS__")] - public bool Minimizable - { - get - { - throw new global::System.NotImplementedException("The member bool AppBarAutomationPeer.Minimizable is not implemented in Uno."); - } - } - #endif - #if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__ - [global::Uno.NotImplemented("__ANDROID__", "__IOS__", "NET461", "__WASM__", "__SKIA__", "__NETSTD_REFERENCE__", "__MACOS__")] - public global::Windows.UI.Xaml.Automation.WindowVisualState VisualState - { - get - { - throw new global::System.NotImplementedException("The member WindowVisualState AppBarAutomationPeer.VisualState is not implemented in Uno."); - } - } - #endif - #if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__ - [global::Uno.NotImplemented("__ANDROID__", "__IOS__", "NET461", "__WASM__", "__SKIA__", "__NETSTD_REFERENCE__", "__MACOS__")] - public AppBarAutomationPeer( global::Windows.UI.Xaml.Controls.AppBar owner) : base(owner) - { - global::Windows.Foundation.Metadata.ApiInformation.TryRaiseNotImplemented("Windows.UI.Xaml.Automation.Peers.AppBarAutomationPeer", "AppBarAutomationPeer.AppBarAutomationPeer(AppBar owner)"); - } - #endif + // Skipping already declared property ExpandCollapseState + // Skipping already declared property ToggleState + // Skipping already declared property InteractionState + // Skipping already declared property IsModal + // Skipping already declared property IsTopmost + // Skipping already declared property Maximizable + // Skipping already declared property Minimizable + // Skipping already declared property VisualState + // Skipping already declared method Windows.UI.Xaml.Automation.Peers.AppBarAutomationPeer.AppBarAutomationPeer(Windows.UI.Xaml.Controls.AppBar) // Forced skipping of method Windows.UI.Xaml.Automation.Peers.AppBarAutomationPeer.AppBarAutomationPeer(Windows.UI.Xaml.Controls.AppBar) // Forced skipping of method Windows.UI.Xaml.Automation.Peers.AppBarAutomationPeer.ToggleState.get - #if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__ - [global::Uno.NotImplemented("__ANDROID__", "__IOS__", "NET461", "__WASM__", "__SKIA__", "__NETSTD_REFERENCE__", "__MACOS__")] - public void Toggle() - { - global::Windows.Foundation.Metadata.ApiInformation.TryRaiseNotImplemented("Windows.UI.Xaml.Automation.Peers.AppBarAutomationPeer", "void AppBarAutomationPeer.Toggle()"); - } - #endif + // Skipping already declared method Windows.UI.Xaml.Automation.Peers.AppBarAutomationPeer.Toggle() // Forced skipping of method Windows.UI.Xaml.Automation.Peers.AppBarAutomationPeer.ExpandCollapseState.get - #if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__ - [global::Uno.NotImplemented("__ANDROID__", "__IOS__", "NET461", "__WASM__", "__SKIA__", "__NETSTD_REFERENCE__", "__MACOS__")] - public void Collapse() - { - global::Windows.Foundation.Metadata.ApiInformation.TryRaiseNotImplemented("Windows.UI.Xaml.Automation.Peers.AppBarAutomationPeer", "void AppBarAutomationPeer.Collapse()"); - } - #endif - #if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__ - [global::Uno.NotImplemented("__ANDROID__", "__IOS__", "NET461", "__WASM__", "__SKIA__", "__NETSTD_REFERENCE__", "__MACOS__")] - public void Expand() - { - global::Windows.Foundation.Metadata.ApiInformation.TryRaiseNotImplemented("Windows.UI.Xaml.Automation.Peers.AppBarAutomationPeer", "void AppBarAutomationPeer.Expand()"); - } - #endif + // Skipping already declared method Windows.UI.Xaml.Automation.Peers.AppBarAutomationPeer.Collapse() + // Skipping already declared method Windows.UI.Xaml.Automation.Peers.AppBarAutomationPeer.Expand() // Forced skipping of method Windows.UI.Xaml.Automation.Peers.AppBarAutomationPeer.IsModal.get // Forced skipping of method Windows.UI.Xaml.Automation.Peers.AppBarAutomationPeer.IsTopmost.get // Forced skipping of method Windows.UI.Xaml.Automation.Peers.AppBarAutomationPeer.Maximizable.get // Forced skipping of method Windows.UI.Xaml.Automation.Peers.AppBarAutomationPeer.Minimizable.get // Forced skipping of method Windows.UI.Xaml.Automation.Peers.AppBarAutomationPeer.InteractionState.get // Forced skipping of method Windows.UI.Xaml.Automation.Peers.AppBarAutomationPeer.VisualState.get - #if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__ - [global::Uno.NotImplemented("__ANDROID__", "__IOS__", "NET461", "__WASM__", "__SKIA__", "__NETSTD_REFERENCE__", "__MACOS__")] - public void Close() - { - global::Windows.Foundation.Metadata.ApiInformation.TryRaiseNotImplemented("Windows.UI.Xaml.Automation.Peers.AppBarAutomationPeer", "void AppBarAutomationPeer.Close()"); - } - #endif - #if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__ - [global::Uno.NotImplemented("__ANDROID__", "__IOS__", "NET461", "__WASM__", "__SKIA__", "__NETSTD_REFERENCE__", "__MACOS__")] - public void SetVisualState( global::Windows.UI.Xaml.Automation.WindowVisualState state) - { - global::Windows.Foundation.Metadata.ApiInformation.TryRaiseNotImplemented("Windows.UI.Xaml.Automation.Peers.AppBarAutomationPeer", "void AppBarAutomationPeer.SetVisualState(WindowVisualState state)"); - } - #endif - #if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__ - [global::Uno.NotImplemented("__ANDROID__", "__IOS__", "NET461", "__WASM__", "__SKIA__", "__NETSTD_REFERENCE__", "__MACOS__")] - public bool WaitForInputIdle( int milliseconds) - { - throw new global::System.NotImplementedException("The member bool AppBarAutomationPeer.WaitForInputIdle(int milliseconds) is not implemented in Uno."); - } - #endif + // Skipping already declared method Windows.UI.Xaml.Automation.Peers.AppBarAutomationPeer.Close() + // Skipping already declared method Windows.UI.Xaml.Automation.Peers.AppBarAutomationPeer.SetVisualState(Windows.UI.Xaml.Automation.WindowVisualState) + // Skipping already declared method Windows.UI.Xaml.Automation.Peers.AppBarAutomationPeer.WaitForInputIdle(int) // Processing: Windows.UI.Xaml.Automation.Provider.IToggleProvider // Processing: Windows.UI.Xaml.Automation.Provider.IExpandCollapseProvider // Processing: Windows.UI.Xaml.Automation.Provider.IWindowProvider diff --git a/src/Uno.UI/Generated/3.0.0.0/Windows.UI.Xaml.Automation.Peers/AppBarButtonAutomationPeer.cs b/src/Uno.UI/Generated/3.0.0.0/Windows.UI.Xaml.Automation.Peers/AppBarButtonAutomationPeer.cs index 9ab986ad2eb1..138ce0c828a7 100644 --- a/src/Uno.UI/Generated/3.0.0.0/Windows.UI.Xaml.Automation.Peers/AppBarButtonAutomationPeer.cs +++ b/src/Uno.UI/Generated/3.0.0.0/Windows.UI.Xaml.Automation.Peers/AppBarButtonAutomationPeer.cs @@ -2,44 +2,17 @@ #pragma warning disable 114 // new keyword hiding namespace Windows.UI.Xaml.Automation.Peers { - #if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__ + #if false || false || false || false || false || false || false [global::Uno.NotImplemented] #endif public partial class AppBarButtonAutomationPeer : global::Windows.UI.Xaml.Automation.Peers.ButtonAutomationPeer,global::Windows.UI.Xaml.Automation.Provider.IExpandCollapseProvider { - #if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__ - [global::Uno.NotImplemented("__ANDROID__", "__IOS__", "NET461", "__WASM__", "__SKIA__", "__NETSTD_REFERENCE__", "__MACOS__")] - public global::Windows.UI.Xaml.Automation.ExpandCollapseState ExpandCollapseState - { - get - { - throw new global::System.NotImplementedException("The member ExpandCollapseState AppBarButtonAutomationPeer.ExpandCollapseState is not implemented in Uno."); - } - } - #endif - #if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__ - [global::Uno.NotImplemented("__ANDROID__", "__IOS__", "NET461", "__WASM__", "__SKIA__", "__NETSTD_REFERENCE__", "__MACOS__")] - public AppBarButtonAutomationPeer( global::Windows.UI.Xaml.Controls.AppBarButton owner) : base(owner) - { - global::Windows.Foundation.Metadata.ApiInformation.TryRaiseNotImplemented("Windows.UI.Xaml.Automation.Peers.AppBarButtonAutomationPeer", "AppBarButtonAutomationPeer.AppBarButtonAutomationPeer(AppBarButton owner)"); - } - #endif + // Skipping already declared property ExpandCollapseState + // Skipping already declared method Windows.UI.Xaml.Automation.Peers.AppBarButtonAutomationPeer.AppBarButtonAutomationPeer(Windows.UI.Xaml.Controls.AppBarButton) // Forced skipping of method Windows.UI.Xaml.Automation.Peers.AppBarButtonAutomationPeer.AppBarButtonAutomationPeer(Windows.UI.Xaml.Controls.AppBarButton) // Forced skipping of method Windows.UI.Xaml.Automation.Peers.AppBarButtonAutomationPeer.ExpandCollapseState.get - #if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__ - [global::Uno.NotImplemented("__ANDROID__", "__IOS__", "NET461", "__WASM__", "__SKIA__", "__NETSTD_REFERENCE__", "__MACOS__")] - public void Collapse() - { - global::Windows.Foundation.Metadata.ApiInformation.TryRaiseNotImplemented("Windows.UI.Xaml.Automation.Peers.AppBarButtonAutomationPeer", "void AppBarButtonAutomationPeer.Collapse()"); - } - #endif - #if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__ - [global::Uno.NotImplemented("__ANDROID__", "__IOS__", "NET461", "__WASM__", "__SKIA__", "__NETSTD_REFERENCE__", "__MACOS__")] - public void Expand() - { - global::Windows.Foundation.Metadata.ApiInformation.TryRaiseNotImplemented("Windows.UI.Xaml.Automation.Peers.AppBarButtonAutomationPeer", "void AppBarButtonAutomationPeer.Expand()"); - } - #endif + // Skipping already declared method Windows.UI.Xaml.Automation.Peers.AppBarButtonAutomationPeer.Collapse() + // Skipping already declared method Windows.UI.Xaml.Automation.Peers.AppBarButtonAutomationPeer.Expand() // Processing: Windows.UI.Xaml.Automation.Provider.IExpandCollapseProvider } } diff --git a/src/Uno.UI/Generated/3.0.0.0/Windows.UI.Xaml.Automation.Peers/AppBarToggleButtonAutomationPeer.cs b/src/Uno.UI/Generated/3.0.0.0/Windows.UI.Xaml.Automation.Peers/AppBarToggleButtonAutomationPeer.cs index 6100343f81ea..eb26011ce9c0 100644 --- a/src/Uno.UI/Generated/3.0.0.0/Windows.UI.Xaml.Automation.Peers/AppBarToggleButtonAutomationPeer.cs +++ b/src/Uno.UI/Generated/3.0.0.0/Windows.UI.Xaml.Automation.Peers/AppBarToggleButtonAutomationPeer.cs @@ -2,18 +2,12 @@ #pragma warning disable 114 // new keyword hiding namespace Windows.UI.Xaml.Automation.Peers { - #if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__ + #if false || false || false || false || false || false || false [global::Uno.NotImplemented] #endif public partial class AppBarToggleButtonAutomationPeer : global::Windows.UI.Xaml.Automation.Peers.ToggleButtonAutomationPeer { - #if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__ - [global::Uno.NotImplemented("__ANDROID__", "__IOS__", "NET461", "__WASM__", "__SKIA__", "__NETSTD_REFERENCE__", "__MACOS__")] - public AppBarToggleButtonAutomationPeer( global::Windows.UI.Xaml.Controls.AppBarToggleButton owner) : base(owner) - { - global::Windows.Foundation.Metadata.ApiInformation.TryRaiseNotImplemented("Windows.UI.Xaml.Automation.Peers.AppBarToggleButtonAutomationPeer", "AppBarToggleButtonAutomationPeer.AppBarToggleButtonAutomationPeer(AppBarToggleButton owner)"); - } - #endif + // Skipping already declared method Windows.UI.Xaml.Automation.Peers.AppBarToggleButtonAutomationPeer.AppBarToggleButtonAutomationPeer(Windows.UI.Xaml.Controls.AppBarToggleButton) // Forced skipping of method Windows.UI.Xaml.Automation.Peers.AppBarToggleButtonAutomationPeer.AppBarToggleButtonAutomationPeer(Windows.UI.Xaml.Controls.AppBarToggleButton) } } diff --git a/src/Uno.UI/Generated/3.0.0.0/Windows.UI.Xaml.Automation.Provider/IWindowProvider.cs b/src/Uno.UI/Generated/3.0.0.0/Windows.UI.Xaml.Automation.Provider/IWindowProvider.cs index 1229b6511a4b..36ced492d33d 100644 --- a/src/Uno.UI/Generated/3.0.0.0/Windows.UI.Xaml.Automation.Provider/IWindowProvider.cs +++ b/src/Uno.UI/Generated/3.0.0.0/Windows.UI.Xaml.Automation.Provider/IWindowProvider.cs @@ -2,61 +2,61 @@ #pragma warning disable 114 // new keyword hiding namespace Windows.UI.Xaml.Automation.Provider { - #if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__ + #if false [global::Uno.NotImplemented] #endif public partial interface IWindowProvider { - #if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__ +#if false global::Windows.UI.Xaml.Automation.WindowInteractionState InteractionState { get; } - #endif - #if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__ +#endif +#if false bool IsModal { get; } - #endif - #if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__ +#endif +#if false bool IsTopmost { get; } - #endif - #if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__ +#endif +#if false bool Maximizable { get; } - #endif - #if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__ +#endif +#if false bool Minimizable { get; } - #endif - #if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__ +#endif +#if false global::Windows.UI.Xaml.Automation.WindowVisualState VisualState { get; } - #endif +#endif // Forced skipping of method Windows.UI.Xaml.Automation.Provider.IWindowProvider.IsModal.get // Forced skipping of method Windows.UI.Xaml.Automation.Provider.IWindowProvider.IsTopmost.get // Forced skipping of method Windows.UI.Xaml.Automation.Provider.IWindowProvider.Maximizable.get // Forced skipping of method Windows.UI.Xaml.Automation.Provider.IWindowProvider.Minimizable.get // Forced skipping of method Windows.UI.Xaml.Automation.Provider.IWindowProvider.InteractionState.get // Forced skipping of method Windows.UI.Xaml.Automation.Provider.IWindowProvider.VisualState.get - #if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__ +#if false void Close(); - #endif - #if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__ +#endif +#if false void SetVisualState( global::Windows.UI.Xaml.Automation.WindowVisualState state); - #endif - #if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__ +#endif +#if false bool WaitForInputIdle( int milliseconds); - #endif +#endif } } diff --git a/src/Uno.UI/Generated/3.0.0.0/Windows.UI.Xaml.Controls.Primitives/CommandBarTemplateSettings.cs b/src/Uno.UI/Generated/3.0.0.0/Windows.UI.Xaml.Controls.Primitives/CommandBarTemplateSettings.cs index ec0fd8377364..763dfd4006b8 100644 --- a/src/Uno.UI/Generated/3.0.0.0/Windows.UI.Xaml.Controls.Primitives/CommandBarTemplateSettings.cs +++ b/src/Uno.UI/Generated/3.0.0.0/Windows.UI.Xaml.Controls.Primitives/CommandBarTemplateSettings.cs @@ -16,36 +16,9 @@ public partial class CommandBarTemplateSettings : global::Windows.UI.Xaml.Depen // Skipping already declared property OverflowContentMinWidth // Skipping already declared property OverflowContentMaxWidth // Skipping already declared property EffectiveOverflowButtonVisibility - #if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__ - [global::Uno.NotImplemented("__ANDROID__", "__IOS__", "NET461", "__WASM__", "__SKIA__", "__NETSTD_REFERENCE__", "__MACOS__")] - public double OverflowContentCompactYTranslation - { - get - { - throw new global::System.NotImplementedException("The member double CommandBarTemplateSettings.OverflowContentCompactYTranslation is not implemented in Uno."); - } - } - #endif - #if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__ - [global::Uno.NotImplemented("__ANDROID__", "__IOS__", "NET461", "__WASM__", "__SKIA__", "__NETSTD_REFERENCE__", "__MACOS__")] - public double OverflowContentHiddenYTranslation - { - get - { - throw new global::System.NotImplementedException("The member double CommandBarTemplateSettings.OverflowContentHiddenYTranslation is not implemented in Uno."); - } - } - #endif - #if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__ - [global::Uno.NotImplemented("__ANDROID__", "__IOS__", "NET461", "__WASM__", "__SKIA__", "__NETSTD_REFERENCE__", "__MACOS__")] - public double OverflowContentMinimalYTranslation - { - get - { - throw new global::System.NotImplementedException("The member double CommandBarTemplateSettings.OverflowContentMinimalYTranslation is not implemented in Uno."); - } - } - #endif + // Skipping already declared property OverflowContentCompactYTranslation + // Skipping already declared property OverflowContentHiddenYTranslation + // Skipping already declared property OverflowContentMinimalYTranslation // Forced skipping of method Windows.UI.Xaml.Controls.Primitives.CommandBarTemplateSettings.ContentHeight.get // Forced skipping of method Windows.UI.Xaml.Controls.Primitives.CommandBarTemplateSettings.OverflowContentClipRect.get // Forced skipping of method Windows.UI.Xaml.Controls.Primitives.CommandBarTemplateSettings.OverflowContentMinWidth.get diff --git a/src/Uno.UI/Generated/3.0.0.0/Windows.UI.Xaml.Controls/AppBarButton.cs b/src/Uno.UI/Generated/3.0.0.0/Windows.UI.Xaml.Controls/AppBarButton.cs index d3f60dabf339..0c77dab3b49f 100644 --- a/src/Uno.UI/Generated/3.0.0.0/Windows.UI.Xaml.Controls/AppBarButton.cs +++ b/src/Uno.UI/Generated/3.0.0.0/Windows.UI.Xaml.Controls/AppBarButton.cs @@ -10,20 +10,7 @@ public partial class AppBarButton : global::Windows.UI.Xaml.Controls.Button,glo // Skipping already declared property Label // Skipping already declared property Icon // Skipping already declared property LabelPosition - #if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__ - [global::Uno.NotImplemented("__ANDROID__", "__IOS__", "NET461", "__WASM__", "__SKIA__", "__NETSTD_REFERENCE__", "__MACOS__")] - public string KeyboardAcceleratorTextOverride - { - get - { - return (string)this.GetValue(KeyboardAcceleratorTextOverrideProperty); - } - set - { - this.SetValue(KeyboardAcceleratorTextOverrideProperty, value); - } - } - #endif + // Skipping already declared property KeyboardAcceleratorTextOverride // Skipping already declared property TemplateSettings // Skipping already declared property IsCompact // Skipping already declared property DynamicOverflowOrder @@ -34,14 +21,7 @@ public string KeyboardAcceleratorTextOverride // Skipping already declared property DynamicOverflowOrderProperty // Skipping already declared property IsInOverflowProperty // Skipping already declared property LabelPositionProperty - #if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__ - [global::Uno.NotImplemented("__ANDROID__", "__IOS__", "NET461", "__WASM__", "__SKIA__", "__NETSTD_REFERENCE__", "__MACOS__")] - public static global::Windows.UI.Xaml.DependencyProperty KeyboardAcceleratorTextOverrideProperty { get; } = - Windows.UI.Xaml.DependencyProperty.Register( - nameof(KeyboardAcceleratorTextOverride), typeof(string), - typeof(global::Windows.UI.Xaml.Controls.AppBarButton), - new FrameworkPropertyMetadata(default(string))); - #endif + // Skipping already declared property KeyboardAcceleratorTextOverrideProperty // Skipping already declared method Windows.UI.Xaml.Controls.AppBarButton.AppBarButton() // Forced skipping of method Windows.UI.Xaml.Controls.AppBarButton.AppBarButton() // Forced skipping of method Windows.UI.Xaml.Controls.AppBarButton.Label.get diff --git a/src/Uno.UI/Generated/3.0.0.0/Windows.UI.Xaml.Controls/AppBarElementContainer.cs b/src/Uno.UI/Generated/3.0.0.0/Windows.UI.Xaml.Controls/AppBarElementContainer.cs index 9e85934d59d5..65df1ff7969c 100644 --- a/src/Uno.UI/Generated/3.0.0.0/Windows.UI.Xaml.Controls/AppBarElementContainer.cs +++ b/src/Uno.UI/Generated/3.0.0.0/Windows.UI.Xaml.Controls/AppBarElementContainer.cs @@ -2,80 +2,18 @@ #pragma warning disable 114 // new keyword hiding namespace Windows.UI.Xaml.Controls { - #if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__ + #if false || false || false || false || false || false || false [global::Uno.NotImplemented] #endif public partial class AppBarElementContainer : global::Windows.UI.Xaml.Controls.ContentControl,global::Windows.UI.Xaml.Controls.ICommandBarElement,global::Windows.UI.Xaml.Controls.ICommandBarElement2 { - #if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__ - [global::Uno.NotImplemented("__ANDROID__", "__IOS__", "NET461", "__WASM__", "__SKIA__", "__NETSTD_REFERENCE__", "__MACOS__")] - public bool IsCompact - { - get - { - return (bool)this.GetValue(IsCompactProperty); - } - set - { - this.SetValue(IsCompactProperty, value); - } - } - #endif - #if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__ - [global::Uno.NotImplemented("__ANDROID__", "__IOS__", "NET461", "__WASM__", "__SKIA__", "__NETSTD_REFERENCE__", "__MACOS__")] - public int DynamicOverflowOrder - { - get - { - return (int)this.GetValue(DynamicOverflowOrderProperty); - } - set - { - this.SetValue(DynamicOverflowOrderProperty, value); - } - } - #endif - #if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__ - [global::Uno.NotImplemented("__ANDROID__", "__IOS__", "NET461", "__WASM__", "__SKIA__", "__NETSTD_REFERENCE__", "__MACOS__")] - public bool IsInOverflow - { - get - { - return (bool)this.GetValue(IsInOverflowProperty); - } - } - #endif - #if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__ - [global::Uno.NotImplemented("__ANDROID__", "__IOS__", "NET461", "__WASM__", "__SKIA__", "__NETSTD_REFERENCE__", "__MACOS__")] - public static global::Windows.UI.Xaml.DependencyProperty DynamicOverflowOrderProperty { get; } = - Windows.UI.Xaml.DependencyProperty.Register( - nameof(DynamicOverflowOrder), typeof(int), - typeof(global::Windows.UI.Xaml.Controls.AppBarElementContainer), - new FrameworkPropertyMetadata(default(int))); - #endif - #if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__ - [global::Uno.NotImplemented("__ANDROID__", "__IOS__", "NET461", "__WASM__", "__SKIA__", "__NETSTD_REFERENCE__", "__MACOS__")] - public static global::Windows.UI.Xaml.DependencyProperty IsCompactProperty { get; } = - Windows.UI.Xaml.DependencyProperty.Register( - nameof(IsCompact), typeof(bool), - typeof(global::Windows.UI.Xaml.Controls.AppBarElementContainer), - new FrameworkPropertyMetadata(default(bool))); - #endif - #if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__ - [global::Uno.NotImplemented("__ANDROID__", "__IOS__", "NET461", "__WASM__", "__SKIA__", "__NETSTD_REFERENCE__", "__MACOS__")] - public static global::Windows.UI.Xaml.DependencyProperty IsInOverflowProperty { get; } = - Windows.UI.Xaml.DependencyProperty.Register( - nameof(IsInOverflow), typeof(bool), - typeof(global::Windows.UI.Xaml.Controls.AppBarElementContainer), - new FrameworkPropertyMetadata(default(bool))); - #endif - #if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__ - [global::Uno.NotImplemented("__ANDROID__", "__IOS__", "NET461", "__WASM__", "__SKIA__", "__NETSTD_REFERENCE__", "__MACOS__")] - public AppBarElementContainer() : base() - { - global::Windows.Foundation.Metadata.ApiInformation.TryRaiseNotImplemented("Windows.UI.Xaml.Controls.AppBarElementContainer", "AppBarElementContainer.AppBarElementContainer()"); - } - #endif + // Skipping already declared property IsCompact + // Skipping already declared property DynamicOverflowOrder + // Skipping already declared property IsInOverflow + // Skipping already declared property DynamicOverflowOrderProperty + // Skipping already declared property IsCompactProperty + // Skipping already declared property IsInOverflowProperty + // Skipping already declared method Windows.UI.Xaml.Controls.AppBarElementContainer.AppBarElementContainer() // Forced skipping of method Windows.UI.Xaml.Controls.AppBarElementContainer.AppBarElementContainer() // Forced skipping of method Windows.UI.Xaml.Controls.AppBarElementContainer.IsCompact.get // Forced skipping of method Windows.UI.Xaml.Controls.AppBarElementContainer.IsCompact.set diff --git a/src/Uno.UI/Generated/3.0.0.0/Windows.UI.Xaml.Controls/AppBarToggleButton.cs b/src/Uno.UI/Generated/3.0.0.0/Windows.UI.Xaml.Controls/AppBarToggleButton.cs index 1b96036525fd..425a8addc9b1 100644 --- a/src/Uno.UI/Generated/3.0.0.0/Windows.UI.Xaml.Controls/AppBarToggleButton.cs +++ b/src/Uno.UI/Generated/3.0.0.0/Windows.UI.Xaml.Controls/AppBarToggleButton.cs @@ -10,20 +10,7 @@ public partial class AppBarToggleButton : global::Windows.UI.Xaml.Controls.ICom // Skipping already declared property Label // Skipping already declared property Icon // Skipping already declared property LabelPosition - #if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__ - [global::Uno.NotImplemented("__ANDROID__", "__IOS__", "NET461", "__WASM__", "__SKIA__", "__NETSTD_REFERENCE__", "__MACOS__")] - public string KeyboardAcceleratorTextOverride - { - get - { - return (string)this.GetValue(KeyboardAcceleratorTextOverrideProperty); - } - set - { - this.SetValue(KeyboardAcceleratorTextOverrideProperty, value); - } - } - #endif + // Skipping already declared property KeyboardAcceleratorTextOverride // Skipping already declared property TemplateSettings // Skipping already declared property IsCompact // Skipping already declared property DynamicOverflowOrder @@ -34,14 +21,7 @@ public string KeyboardAcceleratorTextOverride // Skipping already declared property DynamicOverflowOrderProperty // Skipping already declared property IsInOverflowProperty // Skipping already declared property LabelPositionProperty - #if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__ - [global::Uno.NotImplemented("__ANDROID__", "__IOS__", "NET461", "__WASM__", "__SKIA__", "__NETSTD_REFERENCE__", "__MACOS__")] - public static global::Windows.UI.Xaml.DependencyProperty KeyboardAcceleratorTextOverrideProperty { get; } = - Windows.UI.Xaml.DependencyProperty.Register( - nameof(KeyboardAcceleratorTextOverride), typeof(string), - typeof(global::Windows.UI.Xaml.Controls.AppBarToggleButton), - new FrameworkPropertyMetadata(default(string))); - #endif + // Skipping already declared property KeyboardAcceleratorTextOverrideProperty // Skipping already declared method Windows.UI.Xaml.Controls.AppBarToggleButton.AppBarToggleButton() // Forced skipping of method Windows.UI.Xaml.Controls.AppBarToggleButton.AppBarToggleButton() // Forced skipping of method Windows.UI.Xaml.Controls.AppBarToggleButton.Label.get diff --git a/src/Uno.UI/Generated/3.0.0.0/Windows.UI.Xaml.Controls/BackgroundSizing.cs b/src/Uno.UI/Generated/3.0.0.0/Windows.UI.Xaml.Controls/BackgroundSizing.cs index 17e516289e77..fb14f43cf7ec 100644 --- a/src/Uno.UI/Generated/3.0.0.0/Windows.UI.Xaml.Controls/BackgroundSizing.cs +++ b/src/Uno.UI/Generated/3.0.0.0/Windows.UI.Xaml.Controls/BackgroundSizing.cs @@ -3,6 +3,9 @@ namespace Windows.UI.Xaml.Controls { #if false || false || false || false || false || false || false + #if false || false || false || false || false || false || false + [global::Uno.NotImplemented] + #endif public enum BackgroundSizing { // Skipping already declared field Windows.UI.Xaml.Controls.BackgroundSizing.InnerBorderEdge diff --git a/src/Uno.UI/Generated/3.0.0.0/Windows.UI.Xaml.Controls/CommandBarDefaultLabelPosition.cs b/src/Uno.UI/Generated/3.0.0.0/Windows.UI.Xaml.Controls/CommandBarDefaultLabelPosition.cs index 1c5baf720993..d023c34d1ce3 100644 --- a/src/Uno.UI/Generated/3.0.0.0/Windows.UI.Xaml.Controls/CommandBarDefaultLabelPosition.cs +++ b/src/Uno.UI/Generated/3.0.0.0/Windows.UI.Xaml.Controls/CommandBarDefaultLabelPosition.cs @@ -2,18 +2,12 @@ #pragma warning disable 114 // new keyword hiding namespace Windows.UI.Xaml.Controls { - #if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__ + #if false || false || false || false || false || false || false public enum CommandBarDefaultLabelPosition { - #if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__ - Bottom = 0, - #endif - #if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__ - Right = 1, - #endif - #if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__ - Collapsed = 2, - #endif + // Skipping already declared field Windows.UI.Xaml.Controls.CommandBarDefaultLabelPosition.Bottom + // Skipping already declared field Windows.UI.Xaml.Controls.CommandBarDefaultLabelPosition.Right + // Skipping already declared field Windows.UI.Xaml.Controls.CommandBarDefaultLabelPosition.Collapsed } #endif } diff --git a/src/Uno.UI/Generated/3.0.0.0/Windows.UI.Xaml.Controls/CommandBarDynamicOverflowAction.cs b/src/Uno.UI/Generated/3.0.0.0/Windows.UI.Xaml.Controls/CommandBarDynamicOverflowAction.cs index e9305dc6ed91..6d7ab619ace6 100644 --- a/src/Uno.UI/Generated/3.0.0.0/Windows.UI.Xaml.Controls/CommandBarDynamicOverflowAction.cs +++ b/src/Uno.UI/Generated/3.0.0.0/Windows.UI.Xaml.Controls/CommandBarDynamicOverflowAction.cs @@ -2,15 +2,11 @@ #pragma warning disable 114 // new keyword hiding namespace Windows.UI.Xaml.Controls { - #if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__ + #if false || false || false || false || false || false || false public enum CommandBarDynamicOverflowAction { - #if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__ - AddingToOverflow = 0, - #endif - #if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__ - RemovingFromOverflow = 1, - #endif + // Skipping already declared field Windows.UI.Xaml.Controls.CommandBarDynamicOverflowAction.AddingToOverflow + // Skipping already declared field Windows.UI.Xaml.Controls.CommandBarDynamicOverflowAction.RemovingFromOverflow } #endif } diff --git a/src/Uno.UI/Generated/3.0.0.0/Windows.UI.Xaml.Controls/CommandBarFlyout.cs b/src/Uno.UI/Generated/3.0.0.0/Windows.UI.Xaml.Controls/CommandBarFlyout.cs index 1417c5b1f665..b566e725b9ac 100644 --- a/src/Uno.UI/Generated/3.0.0.0/Windows.UI.Xaml.Controls/CommandBarFlyout.cs +++ b/src/Uno.UI/Generated/3.0.0.0/Windows.UI.Xaml.Controls/CommandBarFlyout.cs @@ -2,7 +2,7 @@ #pragma warning disable 114 // new keyword hiding namespace Windows.UI.Xaml.Controls { - #if false || false || false || false || false || false || false + #if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__ [global::Uno.NotImplemented] #endif public partial class CommandBarFlyout : global::Windows.UI.Xaml.Controls.Primitives.FlyoutBase @@ -27,7 +27,13 @@ public partial class CommandBarFlyout : global::Windows.UI.Xaml.Controls.Primit } } #endif - // Skipping already declared method Windows.UI.Xaml.Controls.CommandBarFlyout.CommandBarFlyout() + #if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__ + [global::Uno.NotImplemented("__ANDROID__", "__IOS__", "NET461", "__WASM__", "__SKIA__", "__NETSTD_REFERENCE__", "__MACOS__")] + public CommandBarFlyout() : base() + { + global::Windows.Foundation.Metadata.ApiInformation.TryRaiseNotImplemented("Windows.UI.Xaml.Controls.CommandBarFlyout", "CommandBarFlyout.CommandBarFlyout()"); + } + #endif // Forced skipping of method Windows.UI.Xaml.Controls.CommandBarFlyout.CommandBarFlyout() // Forced skipping of method Windows.UI.Xaml.Controls.CommandBarFlyout.PrimaryCommands.get // Forced skipping of method Windows.UI.Xaml.Controls.CommandBarFlyout.SecondaryCommands.get diff --git a/src/Uno.UI/Generated/3.0.0.0/Windows.UI.Xaml.Controls/CommandBarLabelPosition.cs b/src/Uno.UI/Generated/3.0.0.0/Windows.UI.Xaml.Controls/CommandBarLabelPosition.cs index 4934c2dcf50e..71cd90705231 100644 --- a/src/Uno.UI/Generated/3.0.0.0/Windows.UI.Xaml.Controls/CommandBarLabelPosition.cs +++ b/src/Uno.UI/Generated/3.0.0.0/Windows.UI.Xaml.Controls/CommandBarLabelPosition.cs @@ -2,15 +2,11 @@ #pragma warning disable 114 // new keyword hiding namespace Windows.UI.Xaml.Controls { - #if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__ + #if false || false || false || false || false || false || false public enum CommandBarLabelPosition { - #if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__ - Default = 0, - #endif - #if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__ - Collapsed = 1, - #endif + // Skipping already declared field Windows.UI.Xaml.Controls.CommandBarLabelPosition.Default + // Skipping already declared field Windows.UI.Xaml.Controls.CommandBarLabelPosition.Collapsed } #endif } diff --git a/src/Uno.UI/Generated/3.0.0.0/Windows.UI.Xaml.Controls/CommandBarOverflowButtonVisibility.cs b/src/Uno.UI/Generated/3.0.0.0/Windows.UI.Xaml.Controls/CommandBarOverflowButtonVisibility.cs index 1d218d98c3ab..3cdcfb4f53fe 100644 --- a/src/Uno.UI/Generated/3.0.0.0/Windows.UI.Xaml.Controls/CommandBarOverflowButtonVisibility.cs +++ b/src/Uno.UI/Generated/3.0.0.0/Windows.UI.Xaml.Controls/CommandBarOverflowButtonVisibility.cs @@ -2,18 +2,12 @@ #pragma warning disable 114 // new keyword hiding namespace Windows.UI.Xaml.Controls { - #if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__ + #if false || false || false || false || false || false || false public enum CommandBarOverflowButtonVisibility { - #if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__ - Auto = 0, - #endif - #if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__ - Visible = 1, - #endif - #if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__ - Collapsed = 2, - #endif + // Skipping already declared field Windows.UI.Xaml.Controls.CommandBarOverflowButtonVisibility.Auto + // Skipping already declared field Windows.UI.Xaml.Controls.CommandBarOverflowButtonVisibility.Visible + // Skipping already declared field Windows.UI.Xaml.Controls.CommandBarOverflowButtonVisibility.Collapsed } #endif } diff --git a/src/Uno.UI/Generated/3.0.0.0/Windows.UI.Xaml.Controls/CommandBarOverflowPresenter.cs b/src/Uno.UI/Generated/3.0.0.0/Windows.UI.Xaml.Controls/CommandBarOverflowPresenter.cs index be228804e0d6..b2a44909a42d 100644 --- a/src/Uno.UI/Generated/3.0.0.0/Windows.UI.Xaml.Controls/CommandBarOverflowPresenter.cs +++ b/src/Uno.UI/Generated/3.0.0.0/Windows.UI.Xaml.Controls/CommandBarOverflowPresenter.cs @@ -2,18 +2,12 @@ #pragma warning disable 114 // new keyword hiding namespace Windows.UI.Xaml.Controls { - #if false || false || NET461 || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || false + #if false || false || false || false || false || false || false [global::Uno.NotImplemented] #endif public partial class CommandBarOverflowPresenter : global::Windows.UI.Xaml.Controls.ItemsControl { - #if false || false || NET461 || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || false - [global::Uno.NotImplemented("NET461", "__WASM__", "__SKIA__", "__NETSTD_REFERENCE__")] - public CommandBarOverflowPresenter() : base() - { - global::Windows.Foundation.Metadata.ApiInformation.TryRaiseNotImplemented("Windows.UI.Xaml.Controls.CommandBarOverflowPresenter", "CommandBarOverflowPresenter.CommandBarOverflowPresenter()"); - } - #endif + // Skipping already declared method Windows.UI.Xaml.Controls.CommandBarOverflowPresenter.CommandBarOverflowPresenter() // Forced skipping of method Windows.UI.Xaml.Controls.CommandBarOverflowPresenter.CommandBarOverflowPresenter() } } diff --git a/src/Uno.UI/Generated/3.0.0.0/Windows.UI.Xaml.Controls/DynamicOverflowItemsChangingEventArgs.cs b/src/Uno.UI/Generated/3.0.0.0/Windows.UI.Xaml.Controls/DynamicOverflowItemsChangingEventArgs.cs index ea52e1a0e48d..879a1a3c2d8c 100644 --- a/src/Uno.UI/Generated/3.0.0.0/Windows.UI.Xaml.Controls/DynamicOverflowItemsChangingEventArgs.cs +++ b/src/Uno.UI/Generated/3.0.0.0/Windows.UI.Xaml.Controls/DynamicOverflowItemsChangingEventArgs.cs @@ -2,28 +2,13 @@ #pragma warning disable 114 // new keyword hiding namespace Windows.UI.Xaml.Controls { - #if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__ + #if false || false || false || false || false || false || false [global::Uno.NotImplemented] #endif public partial class DynamicOverflowItemsChangingEventArgs { - #if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__ - [global::Uno.NotImplemented("__ANDROID__", "__IOS__", "NET461", "__WASM__", "__SKIA__", "__NETSTD_REFERENCE__", "__MACOS__")] - public global::Windows.UI.Xaml.Controls.CommandBarDynamicOverflowAction Action - { - get - { - throw new global::System.NotImplementedException("The member CommandBarDynamicOverflowAction DynamicOverflowItemsChangingEventArgs.Action is not implemented in Uno."); - } - } - #endif - #if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__ - [global::Uno.NotImplemented("__ANDROID__", "__IOS__", "NET461", "__WASM__", "__SKIA__", "__NETSTD_REFERENCE__", "__MACOS__")] - public DynamicOverflowItemsChangingEventArgs() - { - global::Windows.Foundation.Metadata.ApiInformation.TryRaiseNotImplemented("Windows.UI.Xaml.Controls.DynamicOverflowItemsChangingEventArgs", "DynamicOverflowItemsChangingEventArgs.DynamicOverflowItemsChangingEventArgs()"); - } - #endif + // Skipping already declared property Action + // Skipping already declared method Windows.UI.Xaml.Controls.DynamicOverflowItemsChangingEventArgs.DynamicOverflowItemsChangingEventArgs() // Forced skipping of method Windows.UI.Xaml.Controls.DynamicOverflowItemsChangingEventArgs.DynamicOverflowItemsChangingEventArgs() // Forced skipping of method Windows.UI.Xaml.Controls.DynamicOverflowItemsChangingEventArgs.Action.get } diff --git a/src/Uno.UI/Helpers/WinUI/SharedHelpers.cs b/src/Uno.UI/Helpers/WinUI/SharedHelpers.cs index 37f3ffe23dab..c983cbe40bba 100644 --- a/src/Uno.UI/Helpers/WinUI/SharedHelpers.cs +++ b/src/Uno.UI/Helpers/WinUI/SharedHelpers.cs @@ -483,7 +483,7 @@ public static Rect ConvertPhysicalToDips(UIElement xamlRootReference, Rect physi public static bool IsOnXbox() { -#if HAS_UNO +#if HAS_UNO && !(NET461 || __NETSTD_REFERENCE__) if (!s_isOnXboxInitialized) { var deviceFamily = AnalyticsInfo.VersionInfo.DeviceFamily; diff --git a/src/Uno.UI/UI/Xaml/Automation/Provider/IWindowProvider.cs b/src/Uno.UI/UI/Xaml/Automation/Provider/IWindowProvider.cs new file mode 100644 index 000000000000..b22431b2a040 --- /dev/null +++ b/src/Uno.UI/UI/Xaml/Automation/Provider/IWindowProvider.cs @@ -0,0 +1,53 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Windows.UI.Xaml.Automation.Provider +{ + partial interface IWindowProvider + { + + global::Windows.UI.Xaml.Automation.WindowInteractionState InteractionState + { + get; + } + + + bool IsModal + { + get; + } + + + bool IsTopmost + { + get; + } + + + bool Maximizable + { + get; + } + + + bool Minimizable + { + get; + } + + + global::Windows.UI.Xaml.Automation.WindowVisualState VisualState + { + get; + } + void Close(); + + + void SetVisualState(global::Windows.UI.Xaml.Automation.WindowVisualState state); + + + bool WaitForInputIdle(int milliseconds); + + } +} diff --git a/src/Uno.UI/UI/Xaml/Controls/AppBar/AppBar.Partial.cs b/src/Uno.UI/UI/Xaml/Controls/AppBar/AppBar.Partial.cs new file mode 100644 index 000000000000..30612d1dd691 --- /dev/null +++ b/src/Uno.UI/UI/Xaml/Controls/AppBar/AppBar.Partial.cs @@ -0,0 +1,1690 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. +#nullable enable + +#if __IOS__ || __ANDROID__ +#define HAS_NATIVE_COMMANDBAR +#endif + +using System; +using System.Collections.Generic; +using System.Text; +using DirectUI; +using Uno.Disposables; +using Uno.UI; +using Uno.UI.Helpers.WinUI; +using Windows.ApplicationModel.Resources; +using Windows.Foundation; +using Windows.UI.Xaml.Controls.Primitives; +using Windows.UI.Xaml.Input; +using Windows.UI.Xaml.Media; +using Windows.UI.Xaml.Media.Animation; +using Windows.UI.Xaml.Shapes; +using Uno.UI.Extensions; +using static Microsoft.UI.Xaml.Controls._Tracing; +using Uno.UI.Xaml.Input; +using System.Linq; +using Windows.UI.Xaml.Controls; +using Windows.UI.Xaml; +using Popup = Windows.UI.Xaml.Controls.Primitives.Popup; +using Windows.System; +using Windows.UI.Xaml.Automation.Peers; +using Windows.UI.Xaml.Automation; +using Uno.UI.Controls; + +namespace Windows.UI.Xaml.Controls +{ + public partial class AppBar : ContentControl +#if HAS_NATIVE_COMMANDBAR + , ICustomClippingElement +#endif + { + public event EventHandler? Opened; + public event EventHandler? Opening; + public event EventHandler? Closed; + public event EventHandler? Closing; + + private const string TEXT_HUB_SEE_MORE = nameof(TEXT_HUB_SEE_MORE); + private const string TEXT_HUB_SEE_LESS = nameof(TEXT_HUB_SEE_LESS); + private const string UIA_MORE_BUTTON = nameof(UIA_MORE_BUTTON); + private const string UIA_LESS_BUTTON = nameof(UIA_LESS_BUTTON); + + protected Grid? m_tpLayoutRoot; + protected FrameworkElement? m_tpContentRoot; + protected ButtonBase? m_tpExpandButton; + protected WeakReference? m_tpDisplayModesStateGroupRef; + + protected double m_compactHeight; + protected double m_minimalHeight; + + AppBarMode m_Mode; + + // Owner, if this AppBar is owned by a Page using TopAppBar/BottomAppBar. + WeakReference? m_wpOwner; + + SerialDisposable m_contentRootSizeChangedEventHandler = new SerialDisposable(); + SerialDisposable m_windowSizeChangedEventHandler = new SerialDisposable(); + SerialDisposable m_expandButtonClickEventHandler = new SerialDisposable(); + SerialDisposable m_displayModeStateChangedEventHandler = new SerialDisposable(); + +#pragma warning disable CS0414 +#pragma warning disable CS0649 +#pragma warning disable CS0169 + // Focus state to be applied on loaded. + FocusState m_onLoadFocusState; + UIElement? m_layoutTransitionElement; + UIElement? m_overlayLayoutTransitionElement; + private bool _isNativeTemplate; + //UIElement m_parentElementForLTEs; +#pragma warning restore CS0414 +#pragma warning restore CS0649 +#pragma warning restore CS0169 + + + FrameworkElement? m_overlayElement; + SerialDisposable m_overlayElementPointerPressedEventHandler = new SerialDisposable(); + + WeakReference? m_savedFocusedElementWeakRef; + FocusState m_savedFocusState; + + bool m_isInOverlayState; + bool m_isChangingOpenedState; + bool m_hasUpdatedTemplateSettings; + + // We refresh this value in the OnSizeChanged() & OnContentSizeChanged() handlers. + double m_contentHeight; + + bool m_isOverlayVisible; + Storyboard? m_overlayOpeningStoryboard; + Storyboard? m_overlayClosingStoryboard; + + protected double ContentHeight => m_contentHeight; + + public AppBar() + { + m_Mode = AppBarMode.Inline; + m_onLoadFocusState = FocusState.Unfocused; + m_savedFocusState = FocusState.Unfocused; + m_isInOverlayState = false; + m_isChangingOpenedState = false; + m_hasUpdatedTemplateSettings = false; + m_compactHeight = 0d; + m_minimalHeight = 0d; + m_contentHeight = 0d; + m_isOverlayVisible = false; + + PrepareState(); + DefaultStyleKey = typeof(AppBar); + } + + protected virtual void PrepareState() + { + SizeChanged += OnSizeChanged; + + m_windowSizeChangedEventHandler.Disposable = Windows.UI.Xaml.Window.Current.RegisterSizeChangedEvent(OnWindowSizeChanged); + + + this.SetValue(TemplateSettingsProperty, new AppBarTemplateSettings()); + } + + // Note that we need to wait for OnLoaded event to set focus. + // When we get the on opened event children of AppBar will not be populated + // yet which will prevent them from getting focus. + private protected override void OnLoaded() + { + base.OnLoaded(); + + var isOpen = IsOpen; + if (isOpen) + { + OnIsOpenChanged(true); + } + + //UNO TODO + + //if (m_Mode != AppBarMode_Inline) + //{ + // ctl::ComPtr applicationBarService; + // IFC_RETURN(DXamlCore::GetCurrent()->GetApplicationBarService(applicationBarService)); + + // if (m_Mode == AppBarMode_Floating) + // { + // IFC_RETURN(applicationBarService->RegisterApplicationBar(this, m_Mode)); + // } + + // // Focus the AppBar only if this is a Threshold app and if the AppBar that is being loaded is already open. + // isOpen = FALSE; + // IFC_RETURN(get_IsOpen(&isOpen)); + + // if (isOpen) + // { + // auto focusState = (m_onLoadFocusState != xaml::FocusState_Unfocused ? m_onLoadFocusState : xaml::FocusState_Programmatic); + // IFC_RETURN(applicationBarService->FocusApplicationBar(this, focusState)); + // } + + // // Reset the saved focus state + // m_onLoadFocusState = xaml::FocusState_Unfocused; + //} + + UpdateVisualState(); + } + + private void OnLayoutUpdated(object? sender, object e) + { + //if (m_layoutTransitionElement is { }) + //{ + // PositionLTEs(); + //} + } + + private void OnSizeChanged(object sender, SizeChangedEventArgs args) + { + RefreshContentHeight(); + UpdateTemplateSettings(); + + if (GetOwner() is { } pageOwner) + { + // UNO TODO + //pageOwner.AppBarClosedSizeChanged(); + } + } + + internal override void OnPropertyChanged2(DependencyPropertyChangedEventArgs args) + { + if (args.Property == IsOpenProperty) + { + var isOpen = (bool)args.NewValue; + OnIsOpenChanged(isOpen); + + UpdateVisualState(); + } + else if (args.Property == IsStickyProperty) + { + OnIsStickyChanged(); + } + else if (args.Property == ClosedDisplayModeProperty) + { + // UNO TODO + /* + if (m_Mode != AppBarMode.Inline) + { + ctl::ComPtr applicationBarService; + IFC_RETURN(DXamlCore::GetCurrent()->GetApplicationBarService(applicationBarService)); + + IFC_RETURN(applicationBarService->HandleApplicationBarClosedDisplayModeChange(this, m_Mode)); + }*/ + + InvalidateMeasure(); + UpdateVisualState(); + } + else if (args.Property == LightDismissOverlayModeProperty) + { + ReevaluateIsOverlayVisible(); + } + else if (args.Property == IsEnabledProperty) + { + UpdateVisualState(); + } + } + + protected override void OnVisibilityChanged(Visibility oldValue, Visibility newValue) + { + if (GetOwner() is { } pageOwner) + { + // UNO TODO + //pageOwner.AppBarClosedSizeChanged(); + } + } + private void UnregisterEvents() + { + m_contentRootSizeChangedEventHandler.Disposable = null; + m_windowSizeChangedEventHandler.Disposable = null; + m_expandButtonClickEventHandler.Disposable = null; + m_displayModeStateChangedEventHandler.Disposable = null; + m_overlayElementPointerPressedEventHandler.Disposable = null; + + m_tpLayoutRoot = null; + m_tpContentRoot = null; + m_tpExpandButton = null; + m_tpDisplayModesStateGroupRef = null; + + m_overlayClosingStoryboard = null; + m_overlayOpeningStoryboard = null; + } + + private protected override void OnUnloaded() + { + LayoutUpdated -= OnLayoutUpdated; + SizeChanged -= OnSizeChanged; + if (m_isInOverlayState) + { + TeardownOverlayState(); + } + + UnregisterEvents(); + + base.OnUnloaded(); + + } + + protected override void OnApplyTemplate() + { + UnregisterEvents(); + + // Clear our previous template parts. + m_tpLayoutRoot = null; + m_tpContentRoot = null; + m_tpExpandButton = null; + m_tpDisplayModesStateGroupRef = null; + + base.OnApplyTemplate(); + + GetTemplatePart("LayoutRoot", out m_tpLayoutRoot); + GetTemplatePart("ContentRoot", out m_tpContentRoot); + +#if HAS_NATIVE_COMMANDBAR + _isNativeTemplate = Uno.UI.Extensions.DependencyObjectExtensions + .FindFirstChild(this) != null; +#endif + + if (m_tpContentRoot is { }) + { + m_tpContentRoot.SizeChanged += OnContentRootSizeChanged; + m_contentRootSizeChangedEventHandler.Disposable = Disposable.Create(() => m_tpContentRoot.SizeChanged -= OnContentRootSizeChanged); + } + + GetTemplatePart("ExpandButton", out m_tpExpandButton); + + if (m_tpExpandButton == null) + { + // The previous CommandBar template used "MoreButton" for this template part's name, + // so now we're stuck with it, as much as I'd like to converge them.. + GetTemplatePart("MoreButton", out m_tpExpandButton); + } + + if (m_tpExpandButton is { }) + { + m_tpExpandButton.Click += OnExpandButtonClick; + m_expandButtonClickEventHandler.Disposable = Disposable.Create(() => m_tpExpandButton.Click -= OnExpandButtonClick); + + var toolTip = new ToolTip(); + toolTip.Content = DXamlCore.Current.GetLocalizedResourceString(TEXT_HUB_SEE_MORE); + + ToolTipService.SetToolTip(m_tpExpandButton, toolTip); + + var automationName = AutomationProperties.GetName((Button)m_tpExpandButton); + if (automationName == null) + { + automationName = DXamlCore.GetCurrentNoCreate().GetLocalizedResourceString(UIA_MORE_BUTTON); + AutomationProperties.SetName((Button)m_tpExpandButton, automationName); + } + } + + // Query compact & minimal height from resource dictionary. + { + m_compactHeight = ResourceResolver.ResolveTopLevelResourceDouble("AppBarThemeCompactHeight"); + m_minimalHeight = ResourceResolver.ResolveTopLevelResourceDouble("AppBarThemeMinimalHeight"); + } + + // Lookup the animations to use for the window overlay. + if (m_tpLayoutRoot is { }) + { + var gridResources = m_tpLayoutRoot.Resources; + + if (gridResources.TryGetValue("OverlayOpeningAnimation", out var oWindowOverlayOpeningStoryboard) + && oWindowOverlayOpeningStoryboard is Storyboard windowOverlayOpeningStoryboard) + { + m_overlayOpeningStoryboard = windowOverlayOpeningStoryboard; + } + + if (gridResources.TryGetValue("OverlayClosingAnimation", out var oWindowOverlayClosingStoryboard) + && oWindowOverlayClosingStoryboard is Storyboard windowOverlayClosingStoryboard) + { + m_overlayClosingStoryboard = windowOverlayClosingStoryboard; + } + } + + ReevaluateIsOverlayVisible(); + } + +#if HAS_NATIVE_COMMANDBAR + bool ICustomClippingElement.AllowClippingToLayoutSlot => !_isNativeTemplate; + bool ICustomClippingElement.ForceClippingToLayoutSlot => false; +#endif + + protected override Size MeasureOverride(Size availableSize) + { + var size = base.MeasureOverride(availableSize); + + if (_isNativeTemplate) + { + return size; + } + + if (m_Mode == AppBarMode.Top || m_Mode == AppBarMode.Bottom) + { + // regardless of what we desire, settings of alignment or fixed size content, we will always take up full width + size.Width = availableSize.Width; + } + + // Make sure our returned height matches the configured state. + var closedDisplayMode = ClosedDisplayMode; + + size.Height = closedDisplayMode switch + { + AppBarClosedDisplayMode.Compact => m_compactHeight, + AppBarClosedDisplayMode.Minimal => m_minimalHeight, + _ => 0d, + }; + + return size; + } + + protected override Size ArrangeOverride(Size finalSize) + { + var layoutRootDesiredSize = new Size(); + if (m_tpLayoutRoot is { }) + { + layoutRootDesiredSize = m_tpLayoutRoot.DesiredSize; + } + else + { + layoutRootDesiredSize = finalSize; + } + + var baseSize = base.ArrangeOverride(new Size(finalSize.Width, layoutRootDesiredSize.Height)); + + baseSize.Height = finalSize.Height; + + return baseSize; + } + + protected virtual void OnOpening(object e) + { + TryQueryDisplayModesStatesGroup(); + + if (m_Mode == AppBarMode.Inline) + { + //// If we're in a popup that is light-dismissable, then we don't want to set up + //// a light-dismiss layer - the popup will have its own light-dismiss layer, + //// and it can interfere with ours. + var popupAncestor = this.FindFirstParent(); + if (popupAncestor == null || (popupAncestor.IsLightDismissEnabled || popupAncestor.IsSubMenu)) + { + if (!m_isInOverlayState) + { + if (IsInLiveTree) + { + // Setup our LTEs and light-dismiss layer. + SetupOverlayState(); + + if (m_isOverlayVisible) + { + PlayOverlayOpeningAnimation(); + } + } + } + } + + var isSticky = IsSticky; + if (!isSticky) + { + SetFocusOnAppBar(); + } + } + else + { + // Pre-Threshold AppBars were hidden and would get added to the tree upon opening which + // would invoke their loaded handlers to set focus. + // In threshold, hidden appbars are always in the tree, so we have to simulate the same + // behavior by focusing the appbar whenever it opens. + var closedDisplayMode = ClosedDisplayMode; + if (closedDisplayMode == AppBarClosedDisplayMode.Hidden) + { + // UNO TODO + //ctl::ComPtr applicationBarService; + //IFC_RETURN(DXamlCore::GetCurrent()->GetApplicationBarService(applicationBarService)); + + // Determine the focus state + + // UNO TODO + //var focusState = m_onLoadFocusState != FocusState.Unfocused ? m_onLoadFocusState : FocusState.Programmatic; + //IFC_RETURN(applicationBarService->FocusApplicationBar(this, focusState)); + + // Reset the saved focus state + m_onLoadFocusState = FocusState.Unfocused; + } + } + + if (m_tpExpandButton is { }) + { + // Set a tooltip with "See Less" for the expand button. + var toolTip = new ToolTip(); + toolTip.Content = DXamlCore.Current.GetLocalizedResourceString(TEXT_HUB_SEE_LESS); + + ToolTipService.SetToolTip(m_tpExpandButton, toolTip); + + AutomationProperties.SetName(m_tpExpandButton, DXamlCore.GetCurrentNoCreate().GetLocalizedResourceString(UIA_LESS_BUTTON)); + } + + ElementSoundPlayer.RequestInteractionSoundForElement(ElementSoundKind.Show, this); + + Opening?.Invoke(this, e); + } + + + protected virtual void OnOpened(object e) + { + Opened?.Invoke(this, e); + + // UNO TODO + //if (DXamlCore::GetCurrent()->GetHandle()->BackButtonSupported()) + //{ + // IFC_RETURN(BackButtonIntegration_RegisterListener(this)); + //} + + } + + protected virtual void OnClosing(object e) + { + if (m_Mode == AppBarMode.Inline) + { + // Only restore focus if this AppBar isn't in a flyout - if it is, + // then focus will be restored when the flyout closes. + // We'll interfere with that if we restore focus before that time. + var popupAncestor = this.FindFirstParent(); + if (popupAncestor == null || !(popupAncestor.PopupPanel is FlyoutBasePopupPanel)) + { + RestoreSavedFocus(); + } + + if (m_isOverlayVisible && m_isInOverlayState) + { + PlayOverlayClosingAnimation(); + } + } + + if (m_tpExpandButton is { }) + { + // Set a tooltip with "See More" for the expand button. + var tooltipText = DXamlCore.Current.GetLocalizedResourceString(TEXT_HUB_SEE_MORE); + var tooltip = new ToolTip(); + tooltip.Content = tooltipText; + + ToolTipService.SetToolTip(m_tpExpandButton, tooltip); + + // Update the localized accessibility name for expand button with the more app bar button. + AutomationProperties.SetName(m_tpExpandButton, DXamlCore.GetCurrentNoCreate().GetLocalizedResourceString(UIA_MORE_BUTTON)); + } + + // Request a play hide sound for closed + ElementSoundPlayer.RequestInteractionSoundForElement(ElementSoundKind.Hide, this); + + // Raise the event + Closing?.Invoke(this, e); + } + + protected virtual void OnClosed(object e) + { + if (m_Mode == AppBarMode.Inline && m_isInOverlayState) + { + TeardownOverlayState(); + } + + // Raise the event + Closed?.Invoke(this, e); + + // UNO TODO + //IFC_RETURN(BackButtonIntegration_UnregisterListener(this)); + + } + + + internal override TabStopProcessingResult ProcessTabStopOverride( + DependencyObject? focusedElement, + DependencyObject? candidateTabStopElement, + bool isBackward, + bool didCycleFocusAtRootVisualScope) + { + var result = new TabStopProcessingResult() + { + NewTabStop = null, + IsOverriden = false, + }; + + if (m_Mode == AppBarMode.Inline) + { + var isOpen = IsOpen; + var isSticky = IsSticky; + + // We don't override tab-stop behavior for closed or sticky appbars. + if (!isOpen || isSticky) + { + return result; + } + + var isAncestorOfFocusedElement = this.IsAncestorOf(focusedElement); + var isAncestorOfCandidateElement = this.IsAncestorOf(candidateTabStopElement); + + // If the element losing focus is a child of the appbar and the element + // we're losing focus to is not, then we override tab-stop to keep the + // focus within the appbar. + if (isAncestorOfFocusedElement && !isAncestorOfCandidateElement) + { + var newTabStop = isBackward ? FocusManager.FindLastFocusableElement(this) : FocusManager.FindFirstFocusableElement(this); + + if (newTabStop is { }) + { + result.NewTabStop = newTabStop; + result.IsOverriden = true; + } + } + } + + return result; + } + + + private void OnContentRootSizeChanged(object sender, SizeChangedEventArgs args) + { + var didChange = RefreshContentHeight(); + + if (didChange) + { + UpdateTemplateSettings(); + } + } + + private void OnWindowSizeChanged(object sender, Windows.UI.Core.WindowSizeChangedEventArgs e) + { + if (m_Mode == AppBarMode.Inline) + { + TryDismissInlineAppBar(); + } + } + + // floating appbars are managed through vsm. System appbars (as set by page) use + // transitions that are triggered by layout to load, unload and move around. + private protected override void ChangeVisualState(bool useTransitions) + { + base.ChangeVisualState(useTransitions); + + bool ignored = false; + bool isEnabled = false; + bool isOpen = false; + + var closedDisplayMode = AppBarClosedDisplayMode.Hidden; + bool shouldOpenUp = false; + + isEnabled = IsEnabled; + isOpen = IsOpen; + closedDisplayMode = ClosedDisplayMode; + + // We only need to check this if we're going to an opened state. + if (isOpen) + { + shouldOpenUp = GetShouldOpenUp(); + } + + // CommonStates + GoToState(useTransitions, isEnabled ? "Normal" : "Disabled", out ignored); + + // FloatingStates + if (m_Mode == AppBarMode.Floating) + { + GoToState(useTransitions, isOpen ? "FloatingVisible" : "FloatingHidden", out ignored); + } + + // DockPositions + switch (m_Mode) + { + case AppBarMode.Top: + GoToState(useTransitions, "Top", out ignored); + break; + + case AppBarMode.Bottom: + GoToState(useTransitions, "Bottom", out ignored); + break; + + default: + GoToState(useTransitions, "Undocked", out ignored); + break; + } + + // DisplayModeStates + var displayMode = closedDisplayMode switch + { + AppBarClosedDisplayMode.Compact => "Compact", + AppBarClosedDisplayMode.Minimal => "Minimal", + _ => "Hidden", + }; + + var placement = shouldOpenUp ? "Up" : "Down"; + var openState = string.Empty; + + if (isOpen) + { + openState = "Open"; + } else + { + openState = "Closed"; + placement = string.Empty; + } + + ignored = GoToState(useTransitions, $"{displayMode}{openState}{placement}"); + } + + protected override void OnPointerPressed(PointerRoutedEventArgs e) + { + base.OnPointerPressed(e); + + var isOpen = IsOpen; + if (isOpen) + { + var isSticky = IsSticky; + + if (!isSticky) + { + // If the app bar is in a modal-like state, then don't propagate pointer + // events. + e.Handled = true; + } + } + else + { + var closedDisplayMode = ClosedDisplayMode; + if (closedDisplayMode == AppBarClosedDisplayMode.Minimal) + { + IsOpen = true; + e.Handled = true; + } + } + } + + protected override void OnRightTapped(RightTappedRoutedEventArgs e) + { + base.OnRightTapped(e); + + if (m_Mode != AppBarMode.Inline) + { + var pointerDeviceType = e.PointerDeviceType; + if (pointerDeviceType != Windows.Devices.Input.PointerDeviceType.Mouse) + { + return; + } + + var isOpen = IsOpen; + var isHandled = e.Handled; + + if (isOpen && !isHandled) + { + // UNO TODO + //ctl::ComPtr applicationBarService; + //IFC_RETURN(DXamlCore::GetCurrent()->GetApplicationBarService(applicationBarService)); + + //applicationBarService->SetFocusReturnState(xaml::FocusState_Pointer); + //IFC_RETURN(applicationBarService->ToggleApplicationBars()); + + //applicationBarService->ResetFocusReturnState(); + e.Handled = true; + } + } + } + + private void OnIsStickyChanged() + { + if (m_Mode != AppBarMode.Inline) + { + // UNO TODO + //ctl::ComPtr applicationBarService; + //IFC_RETURN(DXamlCore::GetCurrent()->GetApplicationBarService(applicationBarService)); + //IFC_RETURN(applicationBarService->UpdateDismissLayer()); + } + + if (m_overlayElement is { }) + { + var isSticky = IsSticky; + m_overlayElement.IsHitTestVisible = !isSticky; + } + } + + private void OnIsOpenChanged(bool isOpen) + { + // If the AppBar is not live, then wait until it's loaded before + // responding to changes to opened state and firing our Opening/Opened events. + if (!IsInLiveTree) + { + return; + } + + if (m_Mode != AppBarMode.Inline) + { + // UNO TODO + //ctl::ComPtr applicationBarService; + //IFC_RETURN(DXamlCore::GetCurrent()->GetApplicationBarService(applicationBarService)); + + //BOOLEAN hasFocus = FALSE; + //IFC_RETURN(HasFocus(&hasFocus)); + + //if (isOpen) + //{ + // IFC_RETURN(applicationBarService->SaveCurrentFocusedElement(this)); + // IFC_RETURN(applicationBarService->OpenApplicationBar(this, m_Mode)); + + // // If the AppBar does not already have focus (i.e. it was opened programmatically), + // // then focus the AppBar. + // if (!hasFocus) + // { + // IFC_RETURN(applicationBarService->FocusApplicationBar(this, xaml::FocusState_Programmatic)); + // } + //} + //else + //{ + // IFC_RETURN(applicationBarService->CloseApplicationBar(this, m_Mode)); + + // // Only restore the focus to the saved element if we have the focus just before closing. + // // For CommandBar, we also check if the Overflow has focus in the override method "HasFocus" + // if (hasFocus) + // { + // IFC_RETURN(applicationBarService->FocusSavedElement(this)); + // } + //} + + //IFC_RETURN(applicationBarService->UpdateDismissLayer()); + } + + // Flag that we're transitions between opened & closed states. + m_isChangingOpenedState = true; + + // Fire our Opening/Closing events. If we're a legacy app or a badly + // re-templated app, then fire the Opened/Closed events as well. + { + var routedEventArgs = new RoutedEventArgs(this); + + if (isOpen) + { + OnOpening(routedEventArgs); + } + else + { + OnClosing(routedEventArgs); + } + + // We only query the display modes visual state group for post-WinBlue AppBars + // so in cases where we don't have it (either via re-templating or legacy apps) + // fire the Opening/Closing & Opened/Closed events immediately. + // For WinBlue apps, firing the Opening/Closing events as well doesn't + // matter because Blue apps wouldn't have had access to them. + // For post-WinBlue AppBars, we fire the Opening/Closing & Opened/Closed + // events based on our display mode state transitions. + //if (m_tpDisplayModesStateGroup == null) + { + if (isOpen) + { + OnOpened(routedEventArgs); + } + else + { + OnClosed(routedEventArgs); + } + } + } + } + + private void OnIsOpenChangedForAutomation(DependencyPropertyChangedEventArgs args) + { + var isOpen = (bool)args.NewValue; + bool bAutomationListener = false; + + if (isOpen) + { + AutomationPeer.RaiseEventIfListener(this, AutomationEvents.MenuOpened); + } else + { + AutomationPeer.RaiseEventIfListener(this, AutomationEvents.MenuClosed); + } + + // Raise ToggleState Property change event for Automation clients if they are listening for property changed events. + bAutomationListener = AutomationPeer.ListenerExists(AutomationEvents.PropertyChanged); + if (bAutomationListener) + { + var automationPeer = GetAutomationPeer(); + if (automationPeer is AppBarAutomationPeer applicationBarAutomationPeer) + { + applicationBarAutomationPeer.RaiseToggleStatePropertyChangedEvent(args.OldValue, args.NewValue); + applicationBarAutomationPeer.RaiseExpandCollapseAutomationEvent(isOpen); + } + + } + } + + protected override AutomationPeer OnCreateAutomationPeer() + { + AutomationPeer? ppAutomationPeer = null; + + AppBarAutomationPeer spAutomationPeer; + spAutomationPeer = new AppBarAutomationPeer(this); + ppAutomationPeer = spAutomationPeer; + + return ppAutomationPeer; + } + + protected override void OnKeyDown(KeyRoutedEventArgs args) + { + base.OnKeyDown(args); + + bool isHandled = false; + isHandled = args.Handled; + + if (isHandled) + { + return; + } + + var key = args.Key; + if (key == VirtualKey.Escape) + { + bool isAnyAppBarClosed = false; + + if (m_Mode == AppBarMode.Inline) + { + isAnyAppBarClosed = TryDismissInlineAppBar(); + } + else + { + // UNO TODO + //BOOLEAN isSticky = FALSE; + //IFC_RETURN(get_IsSticky(&isSticky)); + + //// If we have focus and the app bar is not sticky close all light-dismiss app bars on ESC + //ctl::ComPtr applicationBarService; + //IFC_RETURN(DXamlCore::GetCurrent()->GetApplicationBarService(applicationBarService)); + + //BOOLEAN hasFocus = FALSE; + //IFC_RETURN(HasFocus(&hasFocus)); + //if (hasFocus) + //{ + // IFC_RETURN(applicationBarService->CloseAllNonStickyAppBars(&isAnyAppBarClosed)); + + // if (isSticky) + // { + // // If the appbar is sticky restore focus to the saved element without closing the appbar + // applicationBarService->SetFocusReturnState(xaml::FocusState_Keyboard); + // IFC_RETURN(applicationBarService->FocusSavedElement(this)); + // applicationBarService->ResetFocusReturnState(); + // } + //} + } + + args.Handled = isAnyAppBarClosed; + } + } + + public void SetOwner(Page pOwner) + { + m_wpOwner = new WeakReference(pOwner); + } + + public Page? GetOwner() + { + if (m_wpOwner != null + && m_wpOwner.TryGetTarget(out var pageOwner) + && pageOwner is { }) + { + return pageOwner; + } + + return null; + } + + protected virtual bool ContainsElement(DependencyObject pElement) + { + bool isAncestorOfElement = false; + + // For AppBar, ContainsElement is equivalent to IsAncestorOf. + // However, ContainsElement is a virtual method, and CommandBar's + // implementation of it also checks the overflow popup separately from + // IsAncestorOf since the popup isn't part of the same visual tree. + isAncestorOfElement = this.IsAncestorOf(pElement); + + return isAncestorOfElement; + } + + protected bool IsExpandButton(UIElement element) + { + return m_tpExpandButton is { } && element == m_tpExpandButton; + } + + private void OnExpandButtonClick(object sender, RoutedEventArgs e) + { + bool bIsOpen = false; + bIsOpen = IsOpen; + IsOpen = !bIsOpen; + } + + private void OnDisplayModesStateChanged(object sender, VisualStateChangedEventArgs pArgs) + { + // We only fire the opened/closed events if we're changing our opened state (either + // from open to closed or closed to open). We don't fire the event if we changed + // between 2 opened states or 2 closed states such as might happen when changing + // closed display mode. + if (m_isChangingOpenedState) + { + // Create the event args we'll use for our Opened/Closed events. + var routedEventArgs = new RoutedEventArgs(this); + + var isOpen = IsOpen; + + if (isOpen) + { + OnOpened(routedEventArgs); + } + else + { + OnClosed(routedEventArgs); + } + + m_isChangingOpenedState = false; + } + } + + protected virtual void UpdateTemplateSettings() + { + // + // AppBar/CommandBar TemplateSettings and how they're used. + // + // The template settings are core to acheiving the desired experience + // for AppBar/CommandBar at least to how it relates to the various + // ClosedDisplayModes. + // + // This comment block will describe how the code uses TemplateSettings + // to achieve the desired bar interation experience which is controlled + // via the ClosedDisplayMode property. + // + // Anatomy of the bar component of an AppBar/CommandBar: + // + // !==================================================! + // ! Clip Rectangle ! + // ! ! + // ! |----------------------------------------------| ! + // ! | | ! + // ! | Content Root | ! + // ! | | ! + // !=|==============================================|=! + // |::::::::::::::::::::::::::::::::::::::::::::::| + // |::::::::::::::::::::::::::::::::::::::::::::::| + // |----------------------------------------------| + // + // * The region covered in '::' is clipped away. + // + // ** The diagram shows the clip rect wider than the content, but + // that is just done to make it more readable. In reality, they + // are the same width. + // + // When we measure and arrange an AppBar/CommandBar, the size we return + // as our desired sized (in the case of measure) and the final size + // (in the case of arrange) depends on the closed display mode. We + // measure our sub-tree normally but we modify the returned height to + // make it match our closed display mode. + // + // This causes the control to get arranged such that the top portion + // of the content root that is within our closed display mode height + // will be visible, while the rest that is below will get covered up + // by other content. It's similar to if we had a negative margin on + // the bottom. + // + // The clip rectangle is then used to make sure this bottom portion does + // not get rendered; so we are left with just the top portion representing + // our closed display mode. + // + // This is where the template settings start to play a part. We need + // to make sure to translate the clip rectangle up by a value that is equal + // to the difference between the content's height and our closed display + // mode height. Since we want to translate up, we have to make that value + // negative, which results in this equation: + // + // VerticalDelta = ClosedDisplayMode_Height - ContentHeight + // + // This value is calculated for each of our supported ClosedDisplayModes + // and is then used in our template & VSM to create the Closed/OpenUp/OpenDown + // experiences. + // + // We apply it in the following ways to achieve our various states: + // + // Closed: + // - Clip Rectangle translated by VerticalDelta (essentially translated up). + // - Content Root not translated. + // + // OpenUp: + // - Clip Rectangle translated by VerticalDelta (essentially translated up). + // - Content Root translated by VerticalDelta (essentially translated up). + // + // OpenDown: + // - Clip Rectangle not translated. + // - Content Root not translated. + // + + var templateSettings = TemplateSettings; + + var actualWidth = ActualWidth; + + var contentHeight = m_contentHeight; + + templateSettings.ClipRect = new Rect(0, 0, actualWidth, contentHeight); + + double compactVerticalDelta = m_compactHeight - contentHeight; + templateSettings.CompactVerticalDelta = compactVerticalDelta; + templateSettings.NegativeCompactVerticalDelta = -compactVerticalDelta; + + double minimalVerticalDelta = m_minimalHeight - contentHeight; + templateSettings.MinimalVerticalDelta = minimalVerticalDelta; + templateSettings.NegativeMinimalVerticalDelta = -minimalVerticalDelta; + + templateSettings.HiddenVerticalDelta = -contentHeight; + templateSettings.NegativeHiddenVerticalDelta = contentHeight; + + if (m_hasUpdatedTemplateSettings) + { + UpdateVisualState(); + + // We wait until after the first call to update template settings to query DisplayModesStates VSG + // to to prevent a performance hit on app startup + TryQueryDisplayModesStatesGroup(); + + // Force animations that reference our template settings in the current visual state + // to update their bindings. + VisualStateGroup? displayModesStateGroup = null; + if (m_tpDisplayModesStateGroupRef?.TryGetTarget(out displayModesStateGroup) ?? false) + { + var currentState = displayModesStateGroup?.CurrentState; + + if (currentState is { }) + { + var storyboard = currentState.Storyboard; + if (storyboard is { }) + { + storyboard.Begin(); + storyboard.SkipToFill(); + } + } + } + } + m_hasUpdatedTemplateSettings = true; + } + + protected bool GetShouldOpenUp() + { + // Top appbars always open down. All other appbars by default + // open up. + bool shouldOpenUp = (m_Mode != AppBarMode.Top); + + // If the appbar is inline, check to see if opening up would + // cause the appbar to appear partially offscreen and if so + // switch to opening down instead. + if (m_Mode == AppBarMode.Inline) + { + var transform = TransformToVisual(null); + + GetVerticalOffsetNeededToOpenUp(out var offsetNeededToOpenUp, out var opensWindowed); + + + // Subtract layout bounds to avoid using the System Tray area to open the AppBar. + var offsetFromRootOpenedUp= transform.TransformPoint(new Point(0, -offsetNeededToOpenUp)); + + var layoutBounds = new Rect(); + + if (opensWindowed) + { + // UNO TODO: Windowed modes are not supported + //wf::Point topLeftPoint = { 0, 0 }; + //IFC_RETURN(transform->TransformPoint(topLeftPoint, &topLeftPoint)); + + //IFC_RETURN(DXamlCore::GetCurrent()->CalculateAvailableMonitorRect(this, topLeftPoint, &layoutBounds)); + } + else + { + layoutBounds = Windows.UI.Xaml.Window.Current.Bounds; + + shouldOpenUp = offsetFromRootOpenedUp.Y >= layoutBounds.Y; + } + } + + return shouldOpenUp; + + } + + protected virtual void GetVerticalOffsetNeededToOpenUp(out double neededOffset, out bool opensWindowed) + { + double verticalDelta = 0d; + var templateSettings = TemplateSettings; + + var closedDisplayMode = ClosedDisplayMode; + + verticalDelta = closedDisplayMode switch + { + AppBarClosedDisplayMode.Compact => templateSettings.CompactVerticalDelta, + AppBarClosedDisplayMode.Minimal => templateSettings.MinimalVerticalDelta, + _ => templateSettings.HiddenVerticalDelta, + }; + + neededOffset = -verticalDelta; + opensWindowed = false; + } + + protected bool TryDismissInlineAppBar() + { + MUX_ASSERT(m_Mode == AppBarMode.Inline); + + bool isAppBarDismissed = false; + + var isSticky = IsSticky; + if (!isSticky) + { + var isOpen = IsOpen; + if (isOpen) + { + isAppBarDismissed = true; + } + + IsOpen = false; + } + + return isAppBarDismissed; + } + + private void SetFocusOnAppBar() + { + MUX_ASSERT(m_Mode == AppBarMode.Inline); + + var focusedElement = this.GetFocusedElement(); + + // Only steal focus if focus isn't already within the appbar. + if (focusedElement is { } && !this.IsAncestorOf(focusedElement)) + { + m_savedFocusedElementWeakRef = new WeakReference(focusedElement); + + if (focusedElement is Control focusedElementAsControl && focusedElementAsControl.FocusState != FocusState.Unfocused) + { + m_savedFocusState = focusedElementAsControl.FocusState; + } + else + { + m_savedFocusState = FocusState.Programmatic; + } + + var firstFocusableElement = FocusManager.FindFirstFocusableElement(this); + if (firstFocusableElement is { }) + { + this.SetFocusedElement(firstFocusableElement, m_savedFocusState, animateIfBringIntoView: false); + } + } + } + + private void RestoreSavedFocus() + { + MUX_ASSERT(m_Mode == AppBarMode.Inline); + + DependencyObject? savedFocusedElement = null; + + _ = m_savedFocusedElementWeakRef?.TryGetTarget(out savedFocusedElement); + + RestoreSavedFocusImpl(savedFocusedElement, m_savedFocusState); + + m_savedFocusedElementWeakRef = null; + + m_savedFocusState = FocusState.Unfocused; + } + + + protected virtual void RestoreSavedFocusImpl(DependencyObject? savedFocusedElement, FocusState savedFocusState) + { + if (savedFocusedElement is { }) + { + this.SetFocusedElement(savedFocusedElement, m_savedFocusState, animateIfBringIntoView: false); + } + } + + private bool RefreshContentHeight() + { + double oldHeight = m_contentHeight; + + if (m_tpContentRoot is { }) + { + m_contentHeight = m_tpContentRoot.ActualHeight; + } + + return oldHeight != m_contentHeight; + } + + private void SetupOverlayState() + { + MUX_ASSERT(m_Mode == AppBarMode.Inline); + MUX_ASSERT(!m_isInOverlayState); + // The approach used to achieve light-dismiss is to create a 1x1 element that is added + // as the first child of our layout root panel. Adding it as the first child ensures that + // it is below our actual content and will therefore not affect the content area's hit-testing. + // We then use a scale transform to scale up an LTE targeted to the element to match the + // dimensions of our window. Finally, we translate that same LTE to make sure it's upper-left + // corner aligns with the window's upper left corner, causing it to cover the entire window. + // A pointer pressed handler is attached to the element to intercept any pointer + // input that is not directed at the actual content. The value of AppBar.IsSticky controls + // whether the light-dismiss element is hit-testable (IsSticky=True -> hit-testable=False). + // The pointer pressed handler simply closes the appbar and marks the routed event args + // message as handled. + if (m_tpLayoutRoot is { }) + { + // Create our overlay element if necessary. + if (m_overlayElement == null) + { + var rectangle = new Rectangle(); + rectangle.Width = 1; + rectangle.Height = 1; + rectangle.UseLayoutRounding = false; + + var isSticky = IsSticky; + rectangle.IsHitTestVisible = !isSticky; + + rectangle.PointerPressed += OnOverlayElementPointerPressed; + m_overlayElementPointerPressedEventHandler.Disposable = Disposable.Create(() => rectangle.PointerPressed -= OnOverlayElementPointerPressed); + + m_overlayElement = rectangle; + + UpdateOverlayElementBrush(); + } + + // Add our overlay element to our layout root panel. + m_tpLayoutRoot.Children.Insert(0, m_overlayElement); + } + + //CreateLTEs(); + + // Update the animations to target the newly created overlay element LTE. + if (m_isOverlayVisible) + { + UpdateTargetForOverlayAnimations(); + } + + m_isInOverlayState = true; + } + + private void TeardownOverlayState() + { + MUX_ASSERT(m_Mode == AppBarMode.Inline); + MUX_ASSERT(m_isInOverlayState); + + //DestroyLTEs(); + + // Remove our light-dismiss element from our layout root panel. + if (m_tpLayoutRoot is { }) + { + var indexOfOverlayElement = m_tpLayoutRoot.Children.IndexOf(m_overlayElement); + MUX_ASSERT(indexOfOverlayElement != -1); + + if (indexOfOverlayElement != -1) + { + m_tpLayoutRoot.Children.RemoveAt(indexOfOverlayElement); + } + } + + m_isInOverlayState = false; + } + + //AppBar::CreateLTEs() + //{ + // ASSERT(!m_layoutTransitionElement); + // ASSERT(!m_overlayLayoutTransitionElement); + // ASSERT(!m_parentElementForLTEs); + + // // If we're under the PopupRoot or FullWindowMediaRoot, then we'll explicitly set + // // our LTE's parent to make sure the LTE doesn't get placed under the TransitionRoot, + // // which is lower in z-order than these other roots. + // if (ShouldUseParentedLTE()) + // { + // ctl::ComPtr parent; + // IFC_RETURN(VisualTreeHelper::GetParentStatic(this, &parent)); + // IFCEXPECT_RETURN(parent); + + // IFC_RETURN(SetPtrValueWithQI(m_parentElementForLTEs, parent.Get())); + // } + + // if (m_overlayElement) + // { + // // Create an LTE for our overlay element. + //IFC_RETURN(LayoutTransitionElement_Create( + // DXamlCore::GetCurrent()->GetHandle(), + // m_overlayElement.Cast()->GetHandle(), + // m_parentElementForLTEs? m_parentElementForLTEs.Cast()->GetHandle() : nullptr, + // false /*isAbsolutelyPositioned*/, + // m_overlayLayoutTransitionElement.ReleaseAndGetAddressOf() + //)); + + // // Configure the overlay LTE. + // { + // ctl::ComPtr overlayLTEPeer; + // IFC_RETURN(DXamlCore::GetCurrent()->GetPeer(m_overlayLayoutTransitionElement.get(), &overlayLTEPeer)); + + // wf::Rect windowBounds = { }; + // IFC_RETURN(DXamlCore::GetCurrent()->GetContentBoundsForElement(GetHandle(), &windowBounds)); + + // ctl::ComPtr compositeTransform; + // IFC_RETURN(ctl::make(&compositeTransform)); + + // IFC_RETURN(compositeTransform->put_ScaleX(windowBounds.Width)); + // IFC_RETURN(compositeTransform->put_ScaleY(windowBounds.Height)); + + // IFC_RETURN(overlayLTEPeer.Cast()->put_RenderTransform(compositeTransform.Get())); + + // ctl::ComPtr transformToVisual; + // IFC_RETURN(m_overlayElement.Cast()->TransformToVisual(nullptr, &transformToVisual)); + + // wf::Point offsetFromRoot = { }; + // IFC_RETURN(transformToVisual->TransformPoint({ 0, 0 }, &offsetFromRoot)); + + // auto flowDirection = xaml::FlowDirection_LeftToRight; + // IFC_RETURN(get_FlowDirection(&flowDirection)); + + // // Translate the light-dismiss layer so that it is positioned at the top-left corner of the window (for LTR cases) + // // or the top-right corner of the window (for RTL cases). + // // TransformToVisual(nullptr) will return an offset relative to the top-left corner of the window regardless of + // // flow direction, so for RTL cases subtract the window width from the returned offset.x value to make it relative + // // to the right edge of the window. + // IFC_RETURN(compositeTransform->put_TranslateX(flowDirection == xaml::FlowDirection_LeftToRight? -offsetFromRoot.X : offsetFromRoot.X - windowBounds.Width)); + // IFC_RETURN(compositeTransform->put_TranslateY(-offsetFromRoot.Y)); + // } + // } + + // IFC_RETURN(LayoutTransitionElement_Create( + // DXamlCore::GetCurrent()->GetHandle(), + // GetHandle(), + // m_parentElementForLTEs ? m_parentElementForLTEs.Cast()->GetHandle() : nullptr, + // false /*isAbsolutelyPositioned*/, + // m_layoutTransitionElement.ReleaseAndGetAddressOf() + // )); + + //// Forward our control's opacity to the LTE since it doesn't happen automatically. + //{ + // double opacity = 0.0; + // IFC_RETURN(get_Opacity(&opacity)); + // IFC_RETURN(m_layoutTransitionElement->SetValueByKnownIndex(KnownPropertyIndex::UIElement_Opacity, static_cast(opacity))); + //} + + //IFC_RETURN(PositionLTEs()); + + //return S_OK; + //} + + //_Check_return_ HRESULT + //AppBar::PositionLTEs() + //{ + // ASSERT(m_layoutTransitionElement); + + // ctl::ComPtr parentDO; + // ctl::ComPtr parent; + + // IFC_RETURN(VisualTreeHelper::GetParentStatic(this, &parentDO)); + + // // If we don't have a parent, then there's nothing for us to do. + // if (parentDO) + // { + // IFC_RETURN(parentDO.As(&parent)); + + // ctl::ComPtr transform; + // IFC_RETURN(TransformToVisual(parent.Cast(), &transform)); + + // wf::Point offset = { }; + // IFC_RETURN(transform->TransformPoint({ 0, 0 }, &offset)); + + // IFC_RETURN(LayoutTransitionElement_SetDestinationOffset(m_layoutTransitionElement, offset.X, offset.Y)); + // } + + // return S_OK; + //} + + //_Check_return_ HRESULT + //AppBar::DestroyLTEs() + //{ + // if (m_layoutTransitionElement) + // { + // IFC_RETURN(LayoutTransitionElement_Destroy( + // DXamlCore::GetCurrent()->GetHandle(), + // GetHandle(), + // m_parentElementForLTEs ? m_parentElementForLTEs.Cast()->GetHandle() : nullptr, + // m_layoutTransitionElement.get() + // )); + + // m_layoutTransitionElement.reset(); + // } + + // if (m_overlayLayoutTransitionElement) + // { + // // Destroy our light-dismiss element's LTE. + // IFC_RETURN(LayoutTransitionElement_Destroy( + // DXamlCore::GetCurrent()->GetHandle(), + // m_overlayElement.Cast()->GetHandle(), + // m_parentElementForLTEs ? m_parentElementForLTEs.Cast()->GetHandle() : nullptr, + // m_overlayLayoutTransitionElement.get() + // )); + + // m_overlayLayoutTransitionElement.reset(); + // } + + // m_parentElementForLTEs.Clear(); + + // return S_OK; + //} + + + private void OnOverlayElementPointerPressed(object sender, PointerRoutedEventArgs e) + { + MUX_ASSERT(m_Mode == AppBarMode.Inline); + + TryDismissInlineAppBar(); + e.Handled = true; + } + + private void TryQueryDisplayModesStatesGroup() + { + if (m_tpDisplayModesStateGroupRef == null) + { + GetTemplatePart("DisplayModeStates", out var displayModesStateGroup); + + m_tpDisplayModesStateGroupRef?.SetTarget(displayModesStateGroup); + + VisualStateGroup? group = null; + if (m_tpDisplayModesStateGroupRef?.TryGetTarget(out group) ?? false) + { + if (group != null) + { + group.CurrentStateChanged += OnDisplayModesStateChanged; + m_displayModeStateChangedEventHandler.Disposable = Disposable.Create(() => group.CurrentStateChanged -= OnDisplayModesStateChanged); + } + } + } + } + + //_Check_return_ HRESULT + //AppBar::OnBackButtonPressedImpl(_Out_ BOOLEAN* pHandled) + //{ + + // BOOLEAN isOpen = FALSE; + // BOOLEAN isSticky = FALSE; + + // IFCPTR_RETURN(pHandled); + + // IFC_RETURN(get_IsOpen(&isOpen)); + // IFC_RETURN(get_IsSticky(&isSticky)); + // if (isOpen && !isSticky) + // { + // IFC_RETURN(put_IsOpen(FALSE)); + // *pHandled = TRUE; + + // if (m_Mode != AppBarMode_Inline) + // { + // ctl::ComPtr spApplicationBarService; + // IFC_RETURN(DXamlCore::GetCurrent()->GetApplicationBarService(spApplicationBarService)); + // IFC_RETURN(spApplicationBarService->CloseAllNonStickyAppBars()); + // } + //} + + //return S_OK; + //} + + private void ReevaluateIsOverlayVisible() + { + bool isOverlayVisible = false; + var overlayMode = LightDismissOverlayMode; + + if (overlayMode == LightDismissOverlayMode.Auto) + { + isOverlayVisible = SharedHelpers.IsOnXbox(); + } + else + { + isOverlayVisible = overlayMode == LightDismissOverlayMode.On; + } + + // Only inline app bars can enable their overlays. Top/Bottom/Floating will use + // the overlay from the ApplicationBarService. + isOverlayVisible = isOverlayVisible && (m_Mode == AppBarMode.Inline); + + if (isOverlayVisible != m_isOverlayVisible) + { + m_isOverlayVisible = isOverlayVisible; + + if (m_isOverlayVisible) + { + if (m_isInOverlayState) + { + UpdateTargetForOverlayAnimations(); + } + } + else + { + // Make sure we've stopped our animations. + if (m_overlayOpeningStoryboard is { }) + { + m_overlayOpeningStoryboard.Stop(); + } + + if (m_overlayClosingStoryboard is { }) + { + m_overlayClosingStoryboard.Stop(); + } + } + + if (m_overlayElement is { }) + { + UpdateOverlayElementBrush(); + } + } + } + + private void UpdateOverlayElementBrush() + { + MUX_ASSERT(m_overlayElement is { }); + + if (m_isOverlayVisible) + { + // Create a theme resource for the overlay brush. + //auto core = DXamlCore::GetCurrent()->GetHandle(); + //auto dictionary = core->GetThemeResources(); + + //xstring_ptr themeBrush; + //IFC_RETURN(xstring_ptr::CloneBuffer(L"AppBarLightDismissOverlayBackground", &themeBrush)); + + //CDependencyObject* initialValueNoRef = nullptr; + //IFC_RETURN(dictionary->GetKeyNoRef(themeBrush, &initialValueNoRef)); + + //CREATEPARAMETERS cp(core); + //xref_ptr themeResourceExtension; + //IFC_RETURN(CThemeResourceExtension::Create( + // reinterpret_cast(themeResourceExtension.ReleaseAndGetAddressOf()), + // &cp)); + + //themeResourceExtension->m_strResourceKey = themeBrush; + + //IFC_RETURN(themeResourceExtension->SetInitialValueAndTargetDictionary(initialValueNoRef, dictionary)); + + //IFC_RETURN(themeResourceExtension->SetThemeResourceBinding( + // m_overlayElement.Cast()->GetHandle(), + // DirectUI::MetadataAPI::GetPropertyByIndex(KnownPropertyIndex::Shape_Fill)) + // ); + + var oBrush = ResourceResolver.ResolveTopLevelResource("AppBarLightDismissOverlayBackground"); + if (oBrush is Brush brush) + { + if (m_overlayElement is Rectangle rectangle) + { + rectangle.Fill = brush; + } + } + } + else + { + var transparentBrush = SolidColorBrushHelper.Transparent; + + if (m_overlayElement is Rectangle rectangle) + { + rectangle.Fill = transparentBrush; + } + } + } + + private void UpdateTargetForOverlayAnimations() + { + //MUX_ASSERT(m_layoutTransitionElement is { }); + MUX_ASSERT(m_isOverlayVisible); + + if (m_overlayOpeningStoryboard is { }) + { + m_overlayOpeningStoryboard.Stop(); + + Storyboard.SetTarget(m_overlayOpeningStoryboard, m_overlayLayoutTransitionElement); + } + + if (m_overlayClosingStoryboard is { }) + { + m_overlayClosingStoryboard.Stop(); + + Storyboard.SetTarget(m_overlayClosingStoryboard, m_overlayLayoutTransitionElement); + } + } + + private void PlayOverlayOpeningAnimation() + { + MUX_ASSERT(m_isInOverlayState); + MUX_ASSERT(m_isOverlayVisible); + + if (m_overlayClosingStoryboard is { }) + { + m_overlayClosingStoryboard.Stop(); + } + + if (m_overlayOpeningStoryboard is { }) + { + m_overlayOpeningStoryboard.Begin(); + } + } + + private void PlayOverlayClosingAnimation() + { + MUX_ASSERT(m_isInOverlayState); + MUX_ASSERT(m_isOverlayVisible); + + if (m_overlayOpeningStoryboard is { }) + { + m_overlayOpeningStoryboard.Stop(); + } + + if (m_overlayClosingStoryboard is { }) + { + m_overlayClosingStoryboard.Begin(); + } + } + + protected void GetTemplatePart(string name, out T? element) where T : class + { + element = GetTemplateChild(name) as T; + } + } +} diff --git a/src/Uno.UI/UI/Xaml/Controls/AppBar/AppBar.Properties.cs b/src/Uno.UI/UI/Xaml/Controls/AppBar/AppBar.Properties.cs new file mode 100644 index 000000000000..2f84fdff13b6 --- /dev/null +++ b/src/Uno.UI/UI/Xaml/Controls/AppBar/AppBar.Properties.cs @@ -0,0 +1,98 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. +#nullable enable + +using System; +using System.Collections.Generic; +using System.Text; +using Windows.UI.Xaml; +using Windows.UI.Xaml.Controls.Primitives; +using Windows.UI.Xaml.Controls; + +namespace Windows.UI.Xaml.Controls +{ + partial class AppBar + { + #region IsSticky + + public bool IsSticky + { + get => (bool)GetValue(IsStickyProperty); + set => SetValue(IsStickyProperty, value); + } + + public static DependencyProperty IsStickyProperty { get; } = + DependencyProperty.Register( + nameof(IsSticky), + typeof(bool), + typeof(AppBar), + new FrameworkPropertyMetadata(default(bool)) + ); + + #endregion + + #region IsOpen + + public bool IsOpen + { + get => (bool)GetValue(IsOpenProperty); + set => SetValue(IsOpenProperty, value); + } + + public static DependencyProperty IsOpenProperty { get; } = + DependencyProperty.Register( + nameof(IsOpen), + typeof(bool), + typeof(AppBar), + new FrameworkPropertyMetadata(default(bool)) + ); + + #endregion + + #region ClosedDisplayMode + + public AppBarClosedDisplayMode ClosedDisplayMode + { + get => (AppBarClosedDisplayMode)GetValue(ClosedDisplayModeProperty); + set => SetValue(ClosedDisplayModeProperty, value); + } + + public static DependencyProperty ClosedDisplayModeProperty { get; } = + DependencyProperty.Register( + nameof(ClosedDisplayMode), + typeof(AppBarClosedDisplayMode), + typeof(AppBar), + new FrameworkPropertyMetadata(AppBarClosedDisplayMode.Compact) + ); + + #endregion + + #region LightDismissOverlayMode + + public LightDismissOverlayMode LightDismissOverlayMode + { + get => (LightDismissOverlayMode)GetValue(LightDismissOverlayModeProperty); + set => SetValue(LightDismissOverlayModeProperty, value); + } + + public static DependencyProperty LightDismissOverlayModeProperty { get; } = + DependencyProperty.Register( + nameof(LightDismissOverlayMode), + typeof(LightDismissOverlayMode), + typeof(AppBar), + new FrameworkPropertyMetadata(default(LightDismissOverlayMode)) + ); + + #endregion + + #region TemplateSettings + public AppBarTemplateSettings TemplateSettings + { + get => (AppBarTemplateSettings)GetValue(TemplateSettingsProperty); + set => SetValue(TemplateSettingsProperty, value); + } + public static DependencyProperty TemplateSettingsProperty { get; } = + DependencyProperty.Register(nameof(TemplateSettings), typeof(AppBarTemplateSettings), typeof(AppBar), new FrameworkPropertyMetadata(null)); + #endregion + } +} diff --git a/src/Uno.UI/UI/Xaml/Controls/AppBar/AppBar.cs b/src/Uno.UI/UI/Xaml/Controls/AppBar/AppBar.cs deleted file mode 100644 index 02df3b455bde..000000000000 --- a/src/Uno.UI/UI/Xaml/Controls/AppBar/AppBar.cs +++ /dev/null @@ -1,199 +0,0 @@ -#if __IOS__ || __ANDROID__ -#define HAS_NATIVE_COMMANDBAR -#endif -using System; -using System.Collections.Generic; -using System.Text; -using Uno.UI; -using Windows.Foundation; -using Windows.UI.Xaml.Controls.Primitives; -using Uno.UI.Controls; -using Uno.UI.Extensions; - -namespace Windows.UI.Xaml.Controls -{ - public partial class AppBar : ContentControl -#if HAS_NATIVE_COMMANDBAR - , ICustomClippingElement -#endif - { - private double _compactHeight; - private double _minimalHeight; -#if HAS_NATIVE_COMMANDBAR - private bool _isNativeTemplate; -#endif - - public AppBar() - { - TemplateSettings = new AppBarTemplateSettings(this); - - SizeChanged += (s, e) => UpdateTemplateSettings(); - } - -#region IsSticky - - public bool IsSticky - { - get => (bool)GetValue(IsStickyProperty); - set => SetValue(IsStickyProperty, value); - } - - public static DependencyProperty IsStickyProperty { get; } = - DependencyProperty.Register( - "IsSticky", - typeof(bool), - typeof(AppBar), - new FrameworkPropertyMetadata(default(bool)) - ); - -#endregion - -#region IsOpen - - public bool IsOpen - { - get => (bool)GetValue(IsOpenProperty); - set => SetValue(IsOpenProperty, value); - } - - public static DependencyProperty IsOpenProperty { get; } = - DependencyProperty.Register( - "IsOpen", - typeof(bool), - typeof(AppBar), - new FrameworkPropertyMetadata(default(bool)) - ); - -#endregion - -#region ClosedDisplayMode - - public AppBarClosedDisplayMode ClosedDisplayMode - { - get => (AppBarClosedDisplayMode)GetValue(ClosedDisplayModeProperty); - set => SetValue(ClosedDisplayModeProperty, value); - } - - public static DependencyProperty ClosedDisplayModeProperty { get; } = - DependencyProperty.Register( - "ClosedDisplayMode", - typeof(AppBarClosedDisplayMode), - typeof(AppBar), - new FrameworkPropertyMetadata(AppBarClosedDisplayMode.Compact) - ); - -#endregion - -#region LightDismissOverlayMode - - public LightDismissOverlayMode LightDismissOverlayMode - { - get => (LightDismissOverlayMode)GetValue(LightDismissOverlayModeProperty); - set => SetValue(LightDismissOverlayModeProperty, value); - } - - public static DependencyProperty LightDismissOverlayModeProperty { get; } = - DependencyProperty.Register( - "LightDismissOverlayMode", - typeof(LightDismissOverlayMode), - typeof(AppBar), - new FrameworkPropertyMetadata(default(LightDismissOverlayMode)) - ); - -#endregion - - public AppBarTemplateSettings TemplateSettings { get; } - - public event EventHandler Closed; - public event EventHandler Opened; - public event EventHandler Closing; - public event EventHandler Opening; - - protected virtual void OnClosed(object e) - { - Closed?.Invoke(this, e); - } - - protected virtual void OnOpened(object e) - { - Opened?.Invoke(this, e); - } - - protected virtual void OnClosing(object e) - { - Closing?.Invoke(this, e); - } - - protected virtual void OnOpening(object e) - { - Opening?.Invoke(this, e); - } - - protected override void OnApplyTemplate() - { - base.OnApplyTemplate(); - - _compactHeight = ResourceResolver.ResolveTopLevelResourceDouble("AppBarThemeCompactHeight"); - _minimalHeight = ResourceResolver.ResolveTopLevelResourceDouble("AppBarThemeMinimalHeight"); - - UpdateTemplateSettings(); - -#if HAS_NATIVE_COMMANDBAR - _isNativeTemplate = Uno.UI.Extensions.DependencyObjectExtensions - .FindFirstChild(this) != null; -#endif - } - - private void UpdateTemplateSettings() - { - var contentHeight = (ContentTemplateRoot as FrameworkElement)?.ActualHeight ?? ActualHeight; - TemplateSettings.ClipRect = new Windows.Foundation.Rect(0, 0, ActualWidth, contentHeight); - - var compactVerticalDelta = _compactHeight - contentHeight; - TemplateSettings.CompactVerticalDelta = compactVerticalDelta; - TemplateSettings.NegativeCompactVerticalDelta = -compactVerticalDelta; - - var minimalVerticalDelta = _minimalHeight - contentHeight; - TemplateSettings.MinimalVerticalDelta = minimalVerticalDelta; - TemplateSettings.NegativeMinimalVerticalDelta = -minimalVerticalDelta; - - TemplateSettings.HiddenVerticalDelta = -contentHeight; - TemplateSettings.NegativeHiddenVerticalDelta = contentHeight; - } - -#if HAS_NATIVE_COMMANDBAR - protected override Size MeasureOverride(Size availableSize) - { - if (_isNativeTemplate) - { - var size = base.MeasureOverride(availableSize); - return size; - } - - // On WinUI the CommandBar does not constraints its children (it only clips them) - // (It's the responsibility of each child to constraint itself) - // Note: This override is used only for the XAML command bar, not the native! - var infinity = new Size(double.PositiveInfinity, double.PositiveInfinity); - var result = base.MeasureOverride(infinity); - - var height = ClosedDisplayMode switch - { - AppBarClosedDisplayMode.Compact => _compactHeight, - AppBarClosedDisplayMode.Minimal => _minimalHeight, - _ => 0 - }; - - return new Size(result.Width, height); - } - - protected override Size ArrangeOverride(Size finalSize) - { - var size = base.ArrangeOverride(finalSize); - return size; - } - - bool ICustomClippingElement.AllowClippingToLayoutSlot => !_isNativeTemplate; - bool ICustomClippingElement.ForceClippingToLayoutSlot => false; -#endif - } -} diff --git a/src/Uno.UI/UI/Xaml/Controls/AppBar/AppBar.xaml b/src/Uno.UI/UI/Xaml/Controls/AppBar/AppBar.xaml index 69e139c35793..1e81b19af7b9 100644 --- a/src/Uno.UI/UI/Xaml/Controls/AppBar/AppBar.xaml +++ b/src/Uno.UI/UI/Xaml/Controls/AppBar/AppBar.xaml @@ -591,6 +591,471 @@ 8,11,12,13 0,5,0,8 + + + + - + + + + + + + +