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 @@
-
+
+ TargetType="CommandBar"
+ xamarin:BasedOn="{StaticResource NativeDefaultCommandBar}" />
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
diff --git a/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/CommandBar/CommandBar_Native_With_Content.xaml b/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/CommandBar/CommandBar_Native_With_Content.xaml
index 67f38cef0968..2ae7f11e9d98 100644
--- a/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/CommandBar/CommandBar_Native_With_Content.xaml
+++ b/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/CommandBar/CommandBar_Native_With_Content.xaml
@@ -47,23 +47,25 @@
Content="Click me (Android only)"
Click="OnClick"
Height="50" />
-
+
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
diff --git a/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/CommandBar/CommandBar_Uppercase_Resource.xaml b/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/CommandBar/CommandBar_Uppercase_Resource.xaml
index 9d0452bd2a80..db43850405b7 100644
--- a/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/CommandBar/CommandBar_Uppercase_Resource.xaml
+++ b/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/CommandBar/CommandBar_Uppercase_Resource.xaml
@@ -1,24 +1,24 @@
-
+
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
diff --git a/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/CommandBar/CustomContent/CommandBar_Page1.xaml b/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/CommandBar/CustomContent/CommandBar_Page1.xaml
index 30db0447dc81..cd6ceaaa0da7 100644
--- a/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/CommandBar/CustomContent/CommandBar_Page1.xaml
+++ b/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/CommandBar/CustomContent/CommandBar_Page1.xaml
@@ -3,6 +3,7 @@
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
+ xmlns:u="using:Uno.UI.Controls"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:xamarin="http://uno.ui/xamarin"
mc:Ignorable="d xamarin"
diff --git a/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/MenuFlyoutTests/MenuFlyoutItem_Click.xaml b/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/MenuFlyoutTests/MenuFlyoutItem_Click.xaml
index 4671954f4406..c65a6d557a97 100644
--- a/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/MenuFlyoutTests/MenuFlyoutItem_Click.xaml
+++ b/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/MenuFlyoutTests/MenuFlyoutItem_Click.xaml
@@ -15,7 +15,7 @@
-
+
@@ -24,6 +24,6 @@
-
+
diff --git a/src/Uno.UI.FluentTheme.v1/Resources/Version1/Priority06/RevealBrush_themeresources.xaml b/src/Uno.UI.FluentTheme.v1/Resources/Version1/Priority06/RevealBrush_themeresources.xaml
index 30c1e38686c4..8b1a99545de6 100644
--- a/src/Uno.UI.FluentTheme.v1/Resources/Version1/Priority06/RevealBrush_themeresources.xaml
+++ b/src/Uno.UI.FluentTheme.v1/Resources/Version1/Priority06/RevealBrush_themeresources.xaml
@@ -1,4 +1,4 @@
-
+
@@ -809,1397 +809,89 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
-
\ No newline at end of file
+
+
+
+
+
+
diff --git a/src/Uno.UI.FluentTheme.v1/themeresources_v1.xaml b/src/Uno.UI.FluentTheme.v1/themeresources_v1.xaml
index 445f599595f9..5a37c7e96a08 100644
--- a/src/Uno.UI.FluentTheme.v1/themeresources_v1.xaml
+++ b/src/Uno.UI.FluentTheme.v1/themeresources_v1.xaml
@@ -6769,1314 +6769,6 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
12,10,0,10
0,12,0,12
0,12,0,4
@@ -12817,7 +11508,77 @@
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
-
-
-
+
-
-
+
+
+
+
+
+
diff --git a/src/Uno.UI.FluentTheme.v2/themeresources_v2.xaml b/src/Uno.UI.FluentTheme.v2/themeresources_v2.xaml
index 4563933aeada..607aa9083c94 100644
--- a/src/Uno.UI.FluentTheme.v2/themeresources_v2.xaml
+++ b/src/Uno.UI.FluentTheme.v2/themeresources_v2.xaml
@@ -1,4 +1,4 @@
-
+
@@ -1043,6 +1043,8 @@
1,1,1,0
1,0,1,1
+ 64
+ 48
160
240
480
@@ -2947,6 +2949,8 @@
1,1,1,0
1,0,1,1
+ 64
+ 48
160
240
480
@@ -4808,6 +4812,8 @@
1,1,1,0
1,0,1,1
+ 64
+ 48
@@ -7726,10 +7732,8 @@
- 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
diff --git a/src/Uno.UI/UI/Xaml/Controls/CommandBar/CommandBarDefaultLabelPosition.cs b/src/Uno.UI/UI/Xaml/Controls/CommandBar/CommandBarDefaultLabelPosition.cs
new file mode 100644
index 000000000000..cec55e3a66e0
--- /dev/null
+++ b/src/Uno.UI/UI/Xaml/Controls/CommandBar/CommandBarDefaultLabelPosition.cs
@@ -0,0 +1,13 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Windows.UI.Xaml.Controls
+{
+ public enum CommandBarDefaultLabelPosition
+ {
+ Bottom,
+ Right,
+ Collapsed,
+ }
+}
diff --git a/src/Uno.UI/UI/Xaml/Controls/CommandBar/CommandBarDynamicOverflowAction.cs b/src/Uno.UI/UI/Xaml/Controls/CommandBar/CommandBarDynamicOverflowAction.cs
new file mode 100644
index 000000000000..3927a2ad7f66
--- /dev/null
+++ b/src/Uno.UI/UI/Xaml/Controls/CommandBar/CommandBarDynamicOverflowAction.cs
@@ -0,0 +1,12 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Windows.UI.Xaml.Controls
+{
+ public enum CommandBarDynamicOverflowAction
+ {
+ AddingToOverflow,
+ RemovingFromOverflow,
+ }
+}
diff --git a/src/Uno.UI/UI/Xaml/Controls/CommandBar/CommandBarElementCollection.Partial.cs b/src/Uno.UI/UI/Xaml/Controls/CommandBar/CommandBarElementCollection.Partial.cs
new file mode 100644
index 000000000000..d27a27ab4710
--- /dev/null
+++ b/src/Uno.UI/UI/Xaml/Controls/CommandBar/CommandBarElementCollection.Partial.cs
@@ -0,0 +1,114 @@
+// 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.Collections;
+using System.Collections.Generic;
+using Windows.Foundation.Collections;
+using Windows.UI.Xaml.Controls;
+
+namespace Windows.UI.Xaml.Controls
+{
+ partial class CommandBarElementCollection
+ {
+ private readonly List _list = new List();
+
+ public void Init(CommandBar parent, bool notifyCollectionChanging)
+ {
+ m_parent = parent;
+ m_notifyCollectionChanging = notifyCollectionChanging;
+ }
+
+ public ICommandBarElement this[int index]
+ {
+ get => _list[index];
+ set => SetAt(index, value);
+ }
+
+ public void SetAt(int index, ICommandBarElement item)
+ {
+ RaiseVectorChanging(CollectionChange.ItemChanged, index);
+ _list[index] = item;
+ RaiseVectorChanged(CollectionChange.ItemChanged, index);
+ }
+
+ public int Count => _list.Count;
+
+ public bool IsReadOnly => ((ICollection)_list).IsReadOnly;
+
+ public event VectorChangedEventHandler? VectorChanged;
+
+ public void Add(ICommandBarElement item) => Append(item);
+ public void Append(ICommandBarElement item)
+ {
+ Insert(Count, item);
+ }
+
+ public void Clear()
+ {
+ RaiseVectorChanging(CollectionChange.Reset, 0);
+ _list.Clear();
+ RaiseVectorChanged(CollectionChange.Reset, 0);
+ }
+ public bool Contains(ICommandBarElement item) => _list.Contains(item);
+
+ public void CopyTo(ICommandBarElement[] array, int arrayIndex) => _list.CopyTo(array, arrayIndex);
+
+ public IEnumerator GetEnumerator() => _list.GetEnumerator();
+
+ public int IndexOf(ICommandBarElement item) => _list.IndexOf(item);
+
+ public void Insert(int index, ICommandBarElement item)
+ {
+ RaiseVectorChanging(CollectionChange.ItemInserted, index);
+ _list.Insert(index, item);
+ RaiseVectorChanged(CollectionChange.ItemInserted, index);
+ }
+
+ public bool Remove(ICommandBarElement item)
+ {
+ var index = _list.IndexOf(item);
+
+ if (index != -1)
+ {
+ RemoveAt(index);
+
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ public void RemoveAt(int index)
+ {
+ RaiseVectorChanging(CollectionChange.ItemRemoved, index);
+ _list.RemoveAt(index);
+ RaiseVectorChanged(CollectionChange.ItemRemoved, index);
+ }
+
+ IEnumerator IEnumerable.GetEnumerator() => this.GetEnumerator();
+
+ private void RaiseVectorChanged(CollectionChange change, int changeIndex)
+ {
+ VectorChangedEventArgs spArgs;
+
+ spArgs = new VectorChangedEventArgs(change, (uint)changeIndex);
+ VectorChanged?.Invoke(this, spArgs);
+
+ }
+
+ private void RaiseVectorChanging(CollectionChange change, int changeIndex)
+ {
+ if (m_notifyCollectionChanging)
+ {
+ if (m_parent is { })
+ {
+ m_parent.NotifyElementVectorChanging(this, change, changeIndex);
+ }
+ }
+ }
+ }
+}
diff --git a/src/Uno.UI/UI/Xaml/Controls/CommandBar/CommandBarElementCollection.Partial.h.cs b/src/Uno.UI/UI/Xaml/Controls/CommandBar/CommandBarElementCollection.Partial.h.cs
new file mode 100644
index 000000000000..04205454fcfd
--- /dev/null
+++ b/src/Uno.UI/UI/Xaml/Controls/CommandBar/CommandBarElementCollection.Partial.h.cs
@@ -0,0 +1,19 @@
+// 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.Collections;
+using System.Collections.Generic;
+using DirectUI;
+using Windows.Foundation.Collections;
+using Windows.UI.Xaml.Controls;
+
+namespace Windows.UI.Xaml.Controls
+{
+ internal partial class CommandBarElementCollection : IObservableVector, IVector
+ {
+ bool m_notifyCollectionChanging = false;
+ CommandBar? m_parent = null;
+ }
+}
diff --git a/src/Uno.UI/UI/Xaml/Controls/CommandBar/CommandBarFlyout.cs b/src/Uno.UI/UI/Xaml/Controls/CommandBar/CommandBarFlyout.cs
deleted file mode 100644
index d8aa75f77ff1..000000000000
--- a/src/Uno.UI/UI/Xaml/Controls/CommandBar/CommandBarFlyout.cs
+++ /dev/null
@@ -1,10 +0,0 @@
-using System;
-
-namespace Windows.UI.Xaml.Controls
-{
- partial class CommandBarFlyout
- {
- //protected override Control CreatePresenter()
- //{ }
- }
-}
diff --git a/src/Uno.UI/UI/Xaml/Controls/CommandBar/CommandBarLabelPosition.cs b/src/Uno.UI/UI/Xaml/Controls/CommandBar/CommandBarLabelPosition.cs
new file mode 100644
index 000000000000..8c985d4e00ec
--- /dev/null
+++ b/src/Uno.UI/UI/Xaml/Controls/CommandBar/CommandBarLabelPosition.cs
@@ -0,0 +1,12 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Windows.UI.Xaml.Controls
+{
+ public enum CommandBarLabelPosition
+ {
+ Default,
+ Collapsed,
+ }
+}
diff --git a/src/Uno.UI/UI/Xaml/Controls/CommandBar/CommandBarOverflowButtonVisibility.cs b/src/Uno.UI/UI/Xaml/Controls/CommandBar/CommandBarOverflowButtonVisibility.cs
new file mode 100644
index 000000000000..454ee20acb94
--- /dev/null
+++ b/src/Uno.UI/UI/Xaml/Controls/CommandBar/CommandBarOverflowButtonVisibility.cs
@@ -0,0 +1,13 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Windows.UI.Xaml.Controls
+{
+ public enum CommandBarOverflowButtonVisibility
+ {
+ Auto,
+ Visible,
+ Collapsed,
+ }
+}
diff --git a/src/Uno.UI/UI/Xaml/Controls/CommandBar/CommandBarOverflowPresenter.cs b/src/Uno.UI/UI/Xaml/Controls/CommandBar/CommandBarOverflowPresenter.cs
index 9ce3925dd8ec..ec27d51c8b78 100644
--- a/src/Uno.UI/UI/Xaml/Controls/CommandBar/CommandBarOverflowPresenter.cs
+++ b/src/Uno.UI/UI/Xaml/Controls/CommandBar/CommandBarOverflowPresenter.cs
@@ -1,12 +1,66 @@
-#if XAMARIN
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License. See LICENSE in the project root for license information.
+
+#nullable enable
+
+using Windows.UI.Xaml;
+using Windows.UI.Xaml.Controls;
+
namespace Windows.UI.Xaml.Controls
{
- public partial class CommandBarOverflowPresenter : ItemsControl
+ public partial class CommandBarOverflowPresenter : ItemsControl
{
- public CommandBarOverflowPresenter() : base()
+ private bool m_useFullWidth;
+ private bool m_shouldOpenUp;
+
+ public CommandBarOverflowPresenter()
{
+ m_useFullWidth = false;
+ m_shouldOpenUp = false;
+#if XAMARIN
ItemsPanel = new ItemsPanelTemplate(() => new StackPanel());
+#endif
+ }
+
+ public void SetDisplayModeState(bool isFullWidth, bool isOpenUp)
+ {
+ m_useFullWidth = isFullWidth;
+ m_shouldOpenUp = isOpenUp;
+
+ UpdateVisualState(false);
+ }
+
+ protected override void OnApplyTemplate()
+ {
+ base.OnApplyTemplate();
+
+ UpdateVisualState(false);
+ }
+
+ private protected override void ChangeVisualState(bool useTransitions)
+ {
+ base.ChangeVisualState(useTransitions);
+
+ if (m_useFullWidth && m_shouldOpenUp)
+ {
+ GoToState(useTransitions, "FullWidthOpenUp");
+ }
+ else if (m_useFullWidth && !m_shouldOpenUp)
+ {
+ GoToState(useTransitions, "FullWidthOpenDown");
+ }
+ else
+ {
+ GoToState(useTransitions, "DisplayModeDefault");
+ }
+ }
+
+ // Uno Specific: Need to clear the ItemContainerStyle so the style will not stay when the commands
+ // are moved from this Secondary ItemsControl to the CommandBar's Primary ItemsControl
+ protected override void ClearContainerForItemOverride(DependencyObject element, object item)
+ {
+ base.ClearContainerForItemOverride(element, item);
+ element.ClearValue(StyleProperty);
}
}
}
-#endif
\ No newline at end of file
diff --git a/src/Uno.UI/UI/Xaml/Controls/CommandBar/CommandBarTemplateSettings.cs b/src/Uno.UI/UI/Xaml/Controls/CommandBar/CommandBarTemplateSettings.cs
index 141f6cfbe97a..bdfa07da9ad6 100644
--- a/src/Uno.UI/UI/Xaml/Controls/CommandBar/CommandBarTemplateSettings.cs
+++ b/src/Uno.UI/UI/Xaml/Controls/CommandBar/CommandBarTemplateSettings.cs
@@ -1,24 +1,124 @@
using Windows.Foundation;
+using Windows.UI.Xaml;
namespace Windows.UI.Xaml.Controls.Primitives
{
public partial class CommandBarTemplateSettings : DependencyObject
{
- private readonly CommandBar _commandBar;
+ internal CommandBarTemplateSettings()
+ {
+
+ }
+
+ public double ContentHeight
+ {
+ get => (double)GetValue(ContentHeightProperty);
+ internal set => SetValue(ContentHeightProperty, value);
+ }
+
+ internal static DependencyProperty ContentHeightProperty { get; } =
+ DependencyProperty.Register(nameof(ContentHeight), typeof(double), typeof(CommandBarTemplateSettings), new FrameworkPropertyMetadata(0.0));
+
+ public Visibility EffectiveOverflowButtonVisibility
+ {
+ get => (Visibility)GetValue(EffectiveOverflowButtonVisibilityProperty);
+ internal set => SetValue(EffectiveOverflowButtonVisibilityProperty, value);
+ }
+
+ internal static DependencyProperty EffectiveOverflowButtonVisibilityProperty { get; } =
+ DependencyProperty.Register(nameof(EffectiveOverflowButtonVisibility), typeof(Visibility), typeof(CommandBarTemplateSettings), new FrameworkPropertyMetadata(default(Visibility)));
+
+ public double NegativeOverflowContentHeight
+ {
+ get => (double)GetValue(NegativeOverflowContentHeightProperty);
+ internal set => SetValue(NegativeOverflowContentHeightProperty, value);
+ }
+
+ internal static DependencyProperty NegativeOverflowContentHeightProperty { get; } =
+ DependencyProperty.Register(nameof(NegativeOverflowContentHeight), typeof(double), typeof(CommandBarTemplateSettings), new FrameworkPropertyMetadata(0.0));
+
+ public Rect OverflowContentClipRect
+ {
+ get => (Rect)GetValue(OverflowContentClipRectProperty);
+ internal set => SetValue(OverflowContentClipRectProperty, value);
+ }
+
+ internal static DependencyProperty OverflowContentClipRectProperty { get; } =
+ DependencyProperty.Register(nameof(OverflowContentClipRect), typeof(Rect), typeof(CommandBarTemplateSettings), new FrameworkPropertyMetadata(new Rect()));
+
+
+ public double OverflowContentHeight
+ {
+ get => (double)GetValue(OverflowContentHeightProperty);
+ internal set => SetValue(OverflowContentHeightProperty, value);
+ }
+
+ internal static DependencyProperty OverflowContentHeightProperty { get; } =
+ DependencyProperty.Register(nameof(OverflowContentHeight), typeof(double), typeof(CommandBarTemplateSettings), new FrameworkPropertyMetadata(0.0));
+
+ public double OverflowContentHorizontalOffset
+ {
+ get => (double)GetValue(OverflowContentHorizontalOffsetProperty);
+ internal set => SetValue(OverflowContentHorizontalOffsetProperty, value);
+ }
+
+ internal static DependencyProperty OverflowContentHorizontalOffsetProperty { get; } =
+ DependencyProperty.Register(nameof(OverflowContentHorizontalOffset), typeof(double), typeof(CommandBarTemplateSettings), new FrameworkPropertyMetadata(0.0));
+
+ public double OverflowContentMaxHeight
+ {
+ get => (double)GetValue(OverflowContentMaxHeightProperty);
+ internal set => SetValue(OverflowContentMaxHeightProperty, value);
+ }
+
+ internal static DependencyProperty OverflowContentMaxHeightProperty { get; } =
+ DependencyProperty.Register(nameof(OverflowContentMaxHeight), typeof(double), typeof(CommandBarTemplateSettings), new FrameworkPropertyMetadata(0.0));
+
+ public double OverflowContentMinWidth
+ {
+ get => (double)GetValue(OverflowContentMinWidthProperty);
+ internal set => SetValue(OverflowContentMinWidthProperty, value);
+ }
+
+ internal static DependencyProperty OverflowContentMinWidthProperty { get; } =
+ DependencyProperty.Register(nameof(OverflowContentMinWidth), typeof(double), typeof(CommandBarTemplateSettings), new FrameworkPropertyMetadata(0.0));
+
+ public double OverflowContentMaxWidth
+ {
+ get => (double)GetValue(OverflowContentMaxWidthProperty);
+ internal set => SetValue(OverflowContentMaxWidthProperty, value);
+ }
+
+ internal static DependencyProperty OverflowContentMaxWidthProperty { get; } =
+ DependencyProperty.Register(nameof(OverflowContentMaxWidth), typeof(double), typeof(CommandBarTemplateSettings), new FrameworkPropertyMetadata(0.0));
+
+
+ public double OverflowContentCompactYTranslation
+ {
+ get => (double)GetValue(OverflowContentCompactYTranslationProperty);
+ internal set => SetValue(OverflowContentCompactYTranslationProperty, value);
+ }
+
+ internal static DependencyProperty OverflowContentCompactYTranslationProperty { get; } =
+ DependencyProperty.Register(nameof(OverflowContentCompactYTranslation), typeof(double), typeof(CommandBarTemplateSettings), new FrameworkPropertyMetadata(0.0));
+
+
+ public double OverflowContentHiddenYTranslation
+ {
+ get => (double)GetValue(OverflowContentHiddenYTranslationProperty);
+ internal set => SetValue(OverflowContentHiddenYTranslationProperty, value);
+ }
+
+ internal static DependencyProperty OverflowContentHiddenYTranslationProperty { get; } =
+ DependencyProperty.Register(nameof(OverflowContentHiddenYTranslation), typeof(double), typeof(CommandBarTemplateSettings), new FrameworkPropertyMetadata(0.0));
- public CommandBarTemplateSettings(CommandBar commandBar)
+ public double OverflowContentMinimalYTranslation
{
- _commandBar = commandBar;
+ get => (double)GetValue(OverflowContentMinimalYTranslationProperty);
+ internal set => SetValue(OverflowContentMinimalYTranslationProperty, value);
}
- public double ContentHeight { get; internal set; }
- public double NegativeOverflowContentHeight { get; internal set; }
- public Rect OverflowContentClipRect { get; internal set; }
- public double OverflowContentHeight { get; internal set; }
- public double OverflowContentHorizontalOffset { get; internal set; }
- public double OverflowContentMaxHeight { get; internal set; }
- public double OverflowContentMinWidth { get; internal set; }
- public double OverflowContentMaxWidth { get; internal set; }
- public Visibility EffectiveOverflowButtonVisibility { get; internal set; }
+ internal static DependencyProperty OverflowContentMinimalYTranslationProperty { get; } =
+ DependencyProperty.Register(nameof(OverflowContentMinimalYTranslation), typeof(double), typeof(CommandBarTemplateSettings), new FrameworkPropertyMetadata(0.0));
}
}
diff --git a/src/Uno.UI/UI/Xaml/Controls/CommandBar/DynamicOverflowItemsChangingEventArgs.cs b/src/Uno.UI/UI/Xaml/Controls/CommandBar/DynamicOverflowItemsChangingEventArgs.cs
new file mode 100644
index 000000000000..101fe7a6c1e9
--- /dev/null
+++ b/src/Uno.UI/UI/Xaml/Controls/CommandBar/DynamicOverflowItemsChangingEventArgs.cs
@@ -0,0 +1,15 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Windows.UI.Xaml.Controls
+{
+ public partial class DynamicOverflowItemsChangingEventArgs
+ {
+ public global::Windows.UI.Xaml.Controls.CommandBarDynamicOverflowAction Action
+ {
+ get;
+ internal set;
+ }
+ }
+}
diff --git a/src/Uno.UI/UI/Xaml/Controls/CommandBar/ICommandBarLabeledElement.cs b/src/Uno.UI/UI/Xaml/Controls/CommandBar/ICommandBarLabeledElement.cs
new file mode 100644
index 000000000000..a16cd05cf703
--- /dev/null
+++ b/src/Uno.UI/UI/Xaml/Controls/CommandBar/ICommandBarLabeledElement.cs
@@ -0,0 +1,12 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Windows.UI.Xaml.Controls
+{
+ internal interface ICommandBarLabeledElement
+ {
+ void SetDefaultLabelPosition(CommandBarDefaultLabelPosition defaultLabelPosition);
+ bool GetHasBottomLabel();
+ }
+}
diff --git a/src/Uno.UI/UI/Xaml/Controls/CommandBar/ICommandBarOverflowElement.cs b/src/Uno.UI/UI/Xaml/Controls/CommandBar/ICommandBarOverflowElement.cs
new file mode 100644
index 000000000000..bd2bb2d9a5b1
--- /dev/null
+++ b/src/Uno.UI/UI/Xaml/Controls/CommandBar/ICommandBarOverflowElement.cs
@@ -0,0 +1,11 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Windows.UI.Xaml.Controls
+{
+ internal interface ICommandBarOverflowElement
+ {
+ bool UseOverflowStyle { get; set; }
+ }
+}
diff --git a/src/Uno.UI/UI/Xaml/Controls/MenuFlyout/MenuFlyout.cs b/src/Uno.UI/UI/Xaml/Controls/MenuFlyout/MenuFlyout.cs
index 1a1aaf7b1348..d642d98e4a01 100644
--- a/src/Uno.UI/UI/Xaml/Controls/MenuFlyout/MenuFlyout.cs
+++ b/src/Uno.UI/UI/Xaml/Controls/MenuFlyout/MenuFlyout.cs
@@ -371,7 +371,10 @@ IMenu IMenu.ParentMenu
Control presenter = GetPresenter();
MenuFlyoutPresenter menuFlyoutPresenter = presenter as MenuFlyoutPresenter;
- menuFlyoutPresenter.IsSubPresenter = value != null;
+ if (menuFlyoutPresenter is { })
+ {
+ menuFlyoutPresenter.IsSubPresenter = value != null;
+ }
}
}
diff --git a/src/Uno.UI/UI/Xaml/Controls/Primitives/ButtonBase/ButtonBase.mux.cs b/src/Uno.UI/UI/Xaml/Controls/Primitives/ButtonBase/ButtonBase.mux.cs
index b6b7cf04d110..ecd6c65a18f1 100644
--- a/src/Uno.UI/UI/Xaml/Controls/Primitives/ButtonBase/ButtonBase.mux.cs
+++ b/src/Uno.UI/UI/Xaml/Controls/Primitives/ButtonBase/ButtonBase.mux.cs
@@ -202,7 +202,7 @@ private void ClearStateFlags()
///
/// Old value.
/// New value.
- private void OnCommandChanged(object oldValue, object newValue)
+ private protected virtual void OnCommandChanged(object oldValue, object newValue)
{
// Remove handler for CanExecuteChanged from the old value
if (_canExecuteChangedHandler.Disposable != null)
diff --git a/src/Uno.UI/UI/Xaml/Input/FocusManager.mux.static.cs b/src/Uno.UI/UI/Xaml/Input/FocusManager.mux.static.cs
index 4b4488144079..715f66e9fc18 100644
--- a/src/Uno.UI/UI/Xaml/Input/FocusManager.mux.static.cs
+++ b/src/Uno.UI/UI/Xaml/Input/FocusManager.mux.static.cs
@@ -509,13 +509,13 @@ private bool SetFocusedElement(
/// Focus direction.
/// True if focus was set.
internal static bool SetFocusedElementWithDirection(
- DependencyObject pElement,
+ DependencyObject? pElement,
FocusState focusState,
bool animateIfBringIntoView,
bool forceBringIntoView,
FocusNavigationDirection focusNavigationDirection)
{
- DependencyObject spElementToFocus = pElement;
+ DependencyObject? spElementToFocus = pElement;
Control? spControlToFocus;
bool pFocusUpdated = false;
diff --git a/src/Uno.UI/UI/Xaml/Media/Animation/DoubleAnimationUsingKeyFrames.cs b/src/Uno.UI/UI/Xaml/Media/Animation/DoubleAnimationUsingKeyFrames.cs
index bb2932a027dc..b8a8f8d1ddcb 100644
--- a/src/Uno.UI/UI/Xaml/Media/Animation/DoubleAnimationUsingKeyFrames.cs
+++ b/src/Uno.UI/UI/Xaml/Media/Animation/DoubleAnimationUsingKeyFrames.cs
@@ -163,7 +163,7 @@ void ITimeline.SkipToFill()
_startingValue = null;
}
- SetValue(_finalValue);//Set property to its final value
+ SetValue(KeyFrames.OrderBy(k => k.KeyTime.TimeSpan).LastOrDefault()?.Value);//Set property to its final value
OnEnd();
}
diff --git a/src/Uno.UI/UI/Xaml/ResourceResolver.cs b/src/Uno.UI/UI/Xaml/ResourceResolver.cs
index 38d84d52c161..bebd13b216eb 100644
--- a/src/Uno.UI/UI/Xaml/ResourceResolver.cs
+++ b/src/Uno.UI/UI/Xaml/ResourceResolver.cs
@@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
+using System.Linq;
using System.Text;
using Microsoft.Extensions.Logging;
using Uno.Diagnostics.Eventing;
@@ -241,8 +242,9 @@ private static bool TryStaticRetrieval(in SpecializedResourceDictionary.Resource
// See https://github.com/dotnet/runtime/issues/56309 for details
var sourcesEnumerator = CurrentScope.Sources.GetEnumerator();
- while(sourcesEnumerator.MoveNext())
+ while (sourcesEnumerator.MoveNext())
{
+
var source = sourcesEnumerator.Current;
var dictionary = (source.Target as FrameworkElement)?.Resources
diff --git a/src/Uno.WinUIRevert/Program.cs b/src/Uno.WinUIRevert/Program.cs
index 1f29c33cd9e4..625613f94266 100644
--- a/src/Uno.WinUIRevert/Program.cs
+++ b/src/Uno.WinUIRevert/Program.cs
@@ -16,7 +16,7 @@ static void Main(string[] args)
DeleteFolder(Path.Combine(basePath, "src", "Uno.UI", "Generated"));
DeleteFolder(Path.Combine(basePath, "src", "Uno.UWP", "Generated"));
DeleteFolder(Path.Combine(basePath, "src", "Uno.UI", "UI", "Composition"));
- DeleteFolder(Path.Combine(basePath, "src", "Uno.UI", "UI", "Xaml", "Controls", "ProgressBar")); // ProgressBar in WinUI is a replacement of the UWP's version.
+ DeleteFolder(Path.Combine(basePath, "src", "Uno.UI", "UI", "Xaml", "Controls", "ProgressBar")); // ProgressBar in WinUI is a replacement of the UWP's version
var compositionPath = Path.Combine(basePath, @"src", "Uno.UWP", "UI", "Composition");
if (Directory.Exists(compositionPath))