diff --git a/components/TabbedCommandBar/OpenSolution.bat b/components/TabbedCommandBar/OpenSolution.bat new file mode 100644 index 00000000..814a56d4 --- /dev/null +++ b/components/TabbedCommandBar/OpenSolution.bat @@ -0,0 +1,3 @@ +@ECHO OFF + +powershell ..\..\tooling\ProjectHeads\GenerateSingleSampleHeads.ps1 -componentPath %CD% %* \ No newline at end of file diff --git a/components/TabbedCommandBar/samples/Assets/TabbedCommandBar.png b/components/TabbedCommandBar/samples/Assets/TabbedCommandBar.png new file mode 100644 index 00000000..518ecb17 Binary files /dev/null and b/components/TabbedCommandBar/samples/Assets/TabbedCommandBar.png differ diff --git a/components/TabbedCommandBar/samples/Dependencies.props b/components/TabbedCommandBar/samples/Dependencies.props new file mode 100644 index 00000000..e622e1df --- /dev/null +++ b/components/TabbedCommandBar/samples/Dependencies.props @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/components/TabbedCommandBar/samples/TabbedCommandBar.Samples.csproj b/components/TabbedCommandBar/samples/TabbedCommandBar.Samples.csproj new file mode 100644 index 00000000..986a3662 --- /dev/null +++ b/components/TabbedCommandBar/samples/TabbedCommandBar.Samples.csproj @@ -0,0 +1,21 @@ + + + TabbedCommandBar + + + + + + + + + + + + PreserveNewest + + + + + + diff --git a/components/TabbedCommandBar/samples/TabbedCommandBar.md b/components/TabbedCommandBar/samples/TabbedCommandBar.md new file mode 100644 index 00000000..581440a3 --- /dev/null +++ b/components/TabbedCommandBar/samples/TabbedCommandBar.md @@ -0,0 +1,30 @@ +--- +title: TabbedCommandBar +author: yoshiask +description: A control for displaying multiple CommandBars in the same space, like Microsoft Office's ribbon. +keywords: TabbedCommandBar, Control, Layout, commandbar, ribbon +dev_langs: + - csharp +category: Controls +subcategory: Layout +discussion-id: 0 +issue-id: 0 +icon: Assets/TabbedCommandBar.png +--- + +The [TabbedCommandBar](/dotnet/api/microsoft.toolkit.uwp.ui.controls.tabbedcommandbar) displays a set of [TabbedCommandBarItem](/dotnet/api/microsoft.toolkit.uwp.ui.controls.tabbedcommandbaritem) in a shared container found in many productivity type apps. It is based off of [NavigationView](/windows/uwp/design/controls-and-patterns/navigationview). + +`TabbedCommandBarItem` can be used to display certain items, and its `IsContextual` property can be set to change the default style into an item that is known from the Office apps to highlight to a user that certain context options are available. +> [!Sample TabbedCommandBarSample] + +## Remarks + +The TabbedCommandBar automatically applies styles to known common controls inside an `AppBarElementContainer`. The following elements have styles: + +- ComboBox +- SplitButton + +> [!NOTE] +> The ComboBox does not allow changing its selection while it is in the overflow flyout. + +The `TabbedCommandBar` does not add any of its own properties. See [NavigationView](/uwp/api/windows.ui.xaml.controls.navigationview#properties) for a list of accessible properties. diff --git a/components/TabbedCommandBar/samples/TabbedCommandBarSample.xaml b/components/TabbedCommandBar/samples/TabbedCommandBarSample.xaml new file mode 100644 index 00000000..2b174253 --- /dev/null +++ b/components/TabbedCommandBar/samples/TabbedCommandBarSample.xaml @@ -0,0 +1,127 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/components/TabbedCommandBar/samples/TabbedCommandBarSample.xaml.cs b/components/TabbedCommandBar/samples/TabbedCommandBarSample.xaml.cs new file mode 100644 index 00000000..bfe468ae --- /dev/null +++ b/components/TabbedCommandBar/samples/TabbedCommandBarSample.xaml.cs @@ -0,0 +1,18 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using CommunityToolkit.WinUI.Controls; + +namespace TabbedCommandBarExperiment.Samples; + +[ToolkitSampleBoolOption("ContextualItem", true, Title = "Show contextual item")] + +[ToolkitSample(id: nameof(TabbedCommandBarSample), "TabbedCommandBar", description: $"A sample for showing how to create and use a {nameof(TabbedCommandBar)} control.")] +public sealed partial class TabbedCommandBarSample : Page +{ + public TabbedCommandBarSample() + { + this.InitializeComponent(); + } +} diff --git a/components/TabbedCommandBar/src/CommunityToolkit.WinUI.Controls.TabbedCommandBar.csproj b/components/TabbedCommandBar/src/CommunityToolkit.WinUI.Controls.TabbedCommandBar.csproj new file mode 100644 index 00000000..b6829868 --- /dev/null +++ b/components/TabbedCommandBar/src/CommunityToolkit.WinUI.Controls.TabbedCommandBar.csproj @@ -0,0 +1,16 @@ + + + TabbedCommandBar + This package contains TabbedCommandBar. + + + CommunityToolkit.WinUI.Controls.TabbedCommandBarRns + + + + + + + $(PackageIdPrefix).$(PackageIdVariant).Controls.$(ToolkitComponentName) + + diff --git a/components/TabbedCommandBar/src/Dependencies.props b/components/TabbedCommandBar/src/Dependencies.props new file mode 100644 index 00000000..e622e1df --- /dev/null +++ b/components/TabbedCommandBar/src/Dependencies.props @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/components/TabbedCommandBar/src/MultiTarget.props b/components/TabbedCommandBar/src/MultiTarget.props new file mode 100644 index 00000000..b11c1942 --- /dev/null +++ b/components/TabbedCommandBar/src/MultiTarget.props @@ -0,0 +1,9 @@ + + + + uwp;wasdk;wpf;wasm;linuxgtk;macos;ios;android; + + \ No newline at end of file diff --git a/components/TabbedCommandBar/src/TabbedCommandBar.cs b/components/TabbedCommandBar/src/TabbedCommandBar.cs new file mode 100644 index 00000000..dd638500 --- /dev/null +++ b/components/TabbedCommandBar/src/TabbedCommandBar.cs @@ -0,0 +1,107 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using NavigationView = Microsoft.UI.Xaml.Controls.NavigationView; +using NavigationViewSelectionChangedEventArgs = Microsoft.UI.Xaml.Controls.NavigationViewSelectionChangedEventArgs; + +namespace CommunityToolkit.WinUI.Controls; + +/// +/// A basic TabbedCommandBar control that houses s +/// +[ContentProperty(Name = nameof(MenuItems))] +[TemplatePart(Name = "PART_TabbedCommandBarContent", Type = typeof(ContentControl))] +[TemplatePart(Name = "PART_TabbedCommandBarContentBorder", Type = typeof(Border))] +[TemplatePart(Name = "PART_TabChangedStoryboard", Type = typeof(Storyboard))] +public partial class TabbedCommandBar : NavigationView +{ + private ContentControl? _tabbedCommandBarContent = null; + private Border? _tabbedCommandBarContentBorder = null; + private Storyboard? _tabChangedStoryboard = null; + + /// + /// The last selected . + /// + private TabbedCommandBarItem? _previousSelectedItem = null; + private long _visibilityChangedToken; + + /// + /// Initializes a new instance of the class. + /// + public TabbedCommandBar() + { + DefaultStyleKey = typeof(TabbedCommandBar); + DefaultStyleResourceUri = new Uri("ms-appx:///CommunityToolkit.WinUI.Controls.TabbedCommandBar/Themes/Generic.xaml"); + + SelectionChanged += SelectedItemChanged; + Loaded += TabbedCommandBar_Loaded; + } + + /// + protected override void OnApplyTemplate() + { + base.OnApplyTemplate(); + + if (_tabbedCommandBarContent != null) + { + _tabbedCommandBarContent.Content = null; + } + + // Get TabbedCommandBarContent first, since setting SelectedItem requires it + _tabbedCommandBarContent = GetTemplateChild("PART_TabbedCommandBarContent") as ContentControl; + _tabbedCommandBarContentBorder = GetTemplateChild("PART_TabbedCommandBarContentBorder") as Border; + _tabChangedStoryboard = GetTemplateChild("TabChangedStoryboard") as Storyboard; + + // TODO: We could maybe optimize and use a lower-level Loaded event for what's hosting the MenuItems + // to set SelectedItem, but then we may have to pull in another template part, so think we're OK + // to do the Loaded event at the top level. + } + + private void TabbedCommandBar_Loaded(object sender, RoutedEventArgs e) + { + // We need to select the item after the template is realized, otherwise the SelectedItem's + // DataTemplate bindings don't properly navigate the visual tree. + SelectedItem = MenuItems.FirstOrDefault(); + } + + private void SelectedItemChanged(NavigationView sender, NavigationViewSelectionChangedEventArgs args) + { + var item = sender.SelectedItem as TabbedCommandBarItem; + if (item == null || item.Visibility == Visibility.Collapsed) + { + // If the item is now hidden, select the first item instead. + // I can't think of any way that the visibiltiy would be null + // and still be selectable, but let's handle it just in case. + sender.SelectedItem = sender.MenuItems.FirstOrDefault(); + return; + } + + // Remove the visibility PropertyChanged handler from the + // previously selected item + if (_previousSelectedItem != null) + { + _previousSelectedItem.UnregisterPropertyChangedCallback(TabbedCommandBarItem.VisibilityProperty, _visibilityChangedToken); + } + + // Register a new visibility PropertyChangedcallback for the + // currently selected item + _previousSelectedItem = item; + _visibilityChangedToken = + _previousSelectedItem.RegisterPropertyChangedCallback(TabbedCommandBarItem.VisibilityProperty, SelectedItemVisibilityChanged); + + // Set the TabbedCommandBar background and start the transition animation + _tabChangedStoryboard?.Begin(); + } + + private void SelectedItemVisibilityChanged(DependencyObject sender, DependencyProperty dp) + { + // If the item is not visible, default to the first tab + if (sender.GetValue(dp) is Visibility vis && vis == Visibility.Collapsed) + { + // FIXME: This will cause WinUI to throw an exception if run + // when the tabs overflow + SelectedItem = MenuItems.FirstOrDefault(); + } + } +} diff --git a/components/TabbedCommandBar/src/TabbedCommandBar.xaml b/components/TabbedCommandBar/src/TabbedCommandBar.xaml new file mode 100644 index 00000000..f80a262b --- /dev/null +++ b/components/TabbedCommandBar/src/TabbedCommandBar.xaml @@ -0,0 +1,338 @@ + + + + + + + + + + + + + + + + + + + + + + + 0,4 + 4,0 + 8 + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/components/TabbedCommandBar/src/TabbedCommandBarItem.cs b/components/TabbedCommandBar/src/TabbedCommandBarItem.cs new file mode 100644 index 00000000..19e45789 --- /dev/null +++ b/components/TabbedCommandBar/src/TabbedCommandBarItem.cs @@ -0,0 +1,123 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace CommunityToolkit.WinUI.Controls; + +/// +/// A to be displayed in a +/// +[TemplatePart(Name = "PrimaryItemsControl", Type = typeof(ItemsControl))] +[TemplatePart(Name = "MoreButton", Type = typeof(Button))] +public partial class TabbedCommandBarItem : CommandBar +{ + private ItemsControl? _primaryItemsControl; + private Button? _moreButton; + + /// + /// Initializes a new instance of the class. + /// + public TabbedCommandBarItem() + { + DefaultStyleKey = typeof(TabbedCommandBarItem); + DefaultStyleResourceUri = new System.Uri("ms-appx:///CommunityToolkit.WinUI.Controls.TabbedCommandBar/Themes/Generic.xaml"); + } + + /// + /// Identifies the property. + /// + public static readonly DependencyProperty HeaderProperty = DependencyProperty.Register( + nameof(Header), + typeof(object), + typeof(TabbedCommandBarItem), + new PropertyMetadata(string.Empty)); + + /// + /// Gets or sets the text or to display in the header of this TabbedCommandBar tab. + /// + public object Header + { + get => (object)GetValue(HeaderProperty); + set => SetValue(HeaderProperty, value); + } + + /// + /// Identifies the property. + /// + public static readonly DependencyProperty IsContextualProperty = DependencyProperty.Register( + nameof(IsContextual), + typeof(bool), + typeof(TabbedCommandBarItem), + new PropertyMetadata(false)); + + /// + /// Gets or sets a value indicating whether this tab is contextual. + /// + public bool IsContextual + { + get => (bool)GetValue(IsContextualProperty); + set => SetValue(IsContextualProperty, value); + } + + /// + /// Identifies the property. + /// + public static readonly DependencyProperty OverflowButtonAlignmentProperty = DependencyProperty.Register( + nameof(OverflowButtonAlignment), + typeof(HorizontalAlignment), + typeof(TabbedCommandBarItem), + new PropertyMetadata(HorizontalAlignment.Left)); + + /// + /// Gets or sets a value indicating the alignment of the command overflow button. + /// + public HorizontalAlignment OverflowButtonAlignment + { + get => (HorizontalAlignment)GetValue(OverflowButtonAlignmentProperty); + set => SetValue(OverflowButtonAlignmentProperty, value); + } + + /// + /// Identifies the property. + /// + public static readonly DependencyProperty CommandAlignmentProperty = DependencyProperty.Register( + nameof(CommandAlignment), + typeof(HorizontalAlignment), + typeof(TabbedCommandBarItem), + new PropertyMetadata(HorizontalAlignment.Stretch)); + + /// + /// Gets or sets a value indicating the alignment of the commands in the . + /// + public HorizontalAlignment CommandAlignment + { + get => (HorizontalAlignment)GetValue(CommandAlignmentProperty); + set => SetValue(CommandAlignmentProperty, value); + } + + /// + protected override void OnApplyTemplate() + { + base.OnApplyTemplate(); + + _primaryItemsControl = GetTemplateChild("PrimaryItemsControl") as ItemsControl; + if (_primaryItemsControl != null) + { + _primaryItemsControl.HorizontalAlignment = CommandAlignment; + RegisterPropertyChangedCallback(CommandAlignmentProperty, (sender, dp) => + { + _primaryItemsControl.HorizontalAlignment = (HorizontalAlignment)sender.GetValue(dp); + }); + } + + _moreButton = GetTemplateChild("MoreButton") as Button; + if (_moreButton != null) + { + _moreButton.HorizontalAlignment = OverflowButtonAlignment; + RegisterPropertyChangedCallback(OverflowButtonAlignmentProperty, (sender, dp) => + { + _moreButton.HorizontalAlignment = (HorizontalAlignment)sender.GetValue(dp); + }); + } + } +} diff --git a/components/TabbedCommandBar/src/TabbedCommandBarItem.xaml b/components/TabbedCommandBar/src/TabbedCommandBarItem.xaml new file mode 100644 index 00000000..4f027b44 --- /dev/null +++ b/components/TabbedCommandBar/src/TabbedCommandBarItem.xaml @@ -0,0 +1,777 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/components/TabbedCommandBar/src/TabbedCommandBarItemTemplateSelector.cs b/components/TabbedCommandBar/src/TabbedCommandBarItemTemplateSelector.cs new file mode 100644 index 00000000..bea08963 --- /dev/null +++ b/components/TabbedCommandBar/src/TabbedCommandBarItemTemplateSelector.cs @@ -0,0 +1,35 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace CommunityToolkit.WinUI.Controls; + +/// +/// used by for determining the style of normal vs. contextual s. +/// +public class TabbedCommandBarItemTemplateSelector : DataTemplateSelector +{ + /// + /// Gets or sets the of a normal . + /// + public DataTemplate? Normal { get; set; } + + /// + /// Gets or sets the of a contextual . + /// + public DataTemplate? Contextual { get; set; } + + /// + protected override DataTemplate SelectTemplateCore(object item) + { +#pragma warning disable CS8603 // Possible null reference return. + return item is TabbedCommandBarItem t && t.IsContextual ? Contextual : Normal; +#pragma warning restore CS8603 // Possible null reference return. + } + + /// + protected override DataTemplate SelectTemplateCore(object item, DependencyObject container) + { + return SelectTemplateCore(item); + } +} diff --git a/components/TabbedCommandBar/src/Themes/Generic.xaml b/components/TabbedCommandBar/src/Themes/Generic.xaml new file mode 100644 index 00000000..7eda0386 --- /dev/null +++ b/components/TabbedCommandBar/src/Themes/Generic.xaml @@ -0,0 +1,10 @@ + + + + + + + + diff --git a/components/TabbedCommandBar/tests/ExampleTabbedCommandBarTestClass.cs b/components/TabbedCommandBar/tests/ExampleTabbedCommandBarTestClass.cs new file mode 100644 index 00000000..934f9eec --- /dev/null +++ b/components/TabbedCommandBar/tests/ExampleTabbedCommandBarTestClass.cs @@ -0,0 +1,134 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using CommunityToolkit.Tooling.TestGen; +using CommunityToolkit.Tests; +using CommunityToolkit.WinUI.Controls; + +namespace TabbedCommandBarExperiment.Tests; + +[TestClass] +public partial class ExampleTabbedCommandBarTestClass : VisualUITestBase +{ + // If you don't need access to UI objects directly or async code, use this pattern. + [TestMethod] + public void SimpleSynchronousExampleTest() + { + var assembly = typeof(TabbedCommandBar).Assembly; + var type = assembly.GetType(typeof(TabbedCommandBar).FullName ?? string.Empty); + + Assert.IsNotNull(type, "Could not find TabbedCommandBar type."); + Assert.AreEqual(typeof(TabbedCommandBar), type, "Type of TabbedCommandBar does not match expected type."); + } + + // If you don't need access to UI objects directly, use this pattern. + [TestMethod] + public async Task SimpleAsyncExampleTest() + { + await Task.Delay(250); + + Assert.IsTrue(true); + } + + // Example that shows how to check for exception throwing. + [TestMethod] + public void SimpleExceptionCheckTest() + { + // If you need to check exceptions occur for invalid inputs, etc... + // Use Assert.ThrowsException to limit the scope to where you expect the error to occur. + // Otherwise, using the ExpectedException attribute could swallow or + // catch other issues in setup code. + Assert.ThrowsException(() => throw new NotImplementedException()); + } + + // The UIThreadTestMethod automatically dispatches to the UI for us to work with UI objects. + [UIThreadTestMethod] + public void SimpleUIAttributeExampleTest() + { + var component = new TabbedCommandBar(); + Assert.IsNotNull(component); + } + + // The UIThreadTestMethod can also easily grab a XAML Page for us by passing its type as a parameter. + // This lets us actually test a control as it would behave within an actual application. + // The page will already be loaded by the time your test is called. + [UIThreadTestMethod] + public void SimpleUIExamplePageTest(ExampleTabbedCommandBarTestPage page) + { + // You can use the Toolkit Visual Tree helpers here to find the component by type or name: + var component = page.FindDescendant(); + + Assert.IsNotNull(component); + + var componentByName = page.FindDescendant("TabbedCommandBarControl"); + + Assert.IsNotNull(componentByName); + } + + // You can still do async work with a UIThreadTestMethod as well. + [UIThreadTestMethod] + public async Task SimpleAsyncUIExamplePageTest(ExampleTabbedCommandBarTestPage page) + { + // This helper can be used to wait for a rendering pass to complete. + // Note, this is already done by loading a Page with the [UIThreadTestMethod] helper. + await CompositionTargetHelper.ExecuteAfterCompositionRenderingAsync(() => { }); + + var component = page.FindDescendant(); + + Assert.IsNotNull(component); + } + + //// ----------------------------- ADVANCED TEST SCENARIOS ----------------------------- + + // If you need to use DataRow, you can use this pattern with the UI dispatch still. + // Otherwise, checkout the UIThreadTestMethod attribute above. + // See https://github.com/CommunityToolkit/Labs-Windows/issues/186 + [TestMethod] + public async Task ComplexAsyncUIExampleTest() + { + await EnqueueAsync(() => + { + var component = new TabbedCommandBar(); + Assert.IsNotNull(component); + }); + } + + // If you want to load other content not within a XAML page using the UIThreadTestMethod above. + // Then you can do that using the Load/UnloadTestContentAsync methods. + [TestMethod] + public async Task ComplexAsyncLoadUIExampleTest() + { + await EnqueueAsync(async () => + { + var component = new TabbedCommandBar(); + Assert.IsNotNull(component); + Assert.IsFalse(component.IsLoaded); + + await LoadTestContentAsync(component); + + Assert.IsTrue(component.IsLoaded); + + await UnloadTestContentAsync(component); + + Assert.IsFalse(component.IsLoaded); + }); + } + + // You can still use the UIThreadTestMethod to remove the extra layer for the dispatcher as well: + [UIThreadTestMethod] + public async Task ComplexAsyncLoadUIExampleWithoutDispatcherTest() + { + var component = new TabbedCommandBar(); + Assert.IsNotNull(component); + Assert.IsFalse(component.IsLoaded); + + await LoadTestContentAsync(component); + + Assert.IsTrue(component.IsLoaded); + + await UnloadTestContentAsync(component); + + Assert.IsFalse(component.IsLoaded); + } +} diff --git a/components/TabbedCommandBar/tests/ExampleTabbedCommandBarTestPage.xaml b/components/TabbedCommandBar/tests/ExampleTabbedCommandBarTestPage.xaml new file mode 100644 index 00000000..7936ebd5 --- /dev/null +++ b/components/TabbedCommandBar/tests/ExampleTabbedCommandBarTestPage.xaml @@ -0,0 +1,14 @@ + + + + + + + diff --git a/components/TabbedCommandBar/tests/ExampleTabbedCommandBarTestPage.xaml.cs b/components/TabbedCommandBar/tests/ExampleTabbedCommandBarTestPage.xaml.cs new file mode 100644 index 00000000..4af6130a --- /dev/null +++ b/components/TabbedCommandBar/tests/ExampleTabbedCommandBarTestPage.xaml.cs @@ -0,0 +1,16 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace TabbedCommandBarExperiment.Tests; + +/// +/// An empty page that can be used on its own or navigated to within a Frame. +/// +public sealed partial class ExampleTabbedCommandBarTestPage : Page +{ + public ExampleTabbedCommandBarTestPage() + { + this.InitializeComponent(); + } +} diff --git a/components/TabbedCommandBar/tests/TabbedCommandBar.Tests.projitems b/components/TabbedCommandBar/tests/TabbedCommandBar.Tests.projitems new file mode 100644 index 00000000..c3a7b7eb --- /dev/null +++ b/components/TabbedCommandBar/tests/TabbedCommandBar.Tests.projitems @@ -0,0 +1,23 @@ + + + + $(MSBuildAllProjects);$(MSBuildThisFileFullPath) + true + 254FF722-89D0-4EEE-8DA3-BE527A57A16E + + + TabbedCommandBarExperiment.Tests + + + + + ExampleTabbedCommandBarTestPage.xaml + + + + + Designer + MSBuild:Compile + + + \ No newline at end of file diff --git a/components/TabbedCommandBar/tests/TabbedCommandBar.Tests.shproj b/components/TabbedCommandBar/tests/TabbedCommandBar.Tests.shproj new file mode 100644 index 00000000..eb9f6074 --- /dev/null +++ b/components/TabbedCommandBar/tests/TabbedCommandBar.Tests.shproj @@ -0,0 +1,13 @@ + + + + 254FF722-89D0-4EEE-8DA3-BE527A57A16E + 14.0 + + + + + + + +