diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 6442a92ccc0..40970d5aab9 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -42,6 +42,7 @@ Windows 10 Build Number: - [ ] April 2018 Update (17134) - [ ] October 2018 Update (17763) - [ ] May 2019 Update (18362) +- [ ] November 2019 Update (18363) - [ ] Insider Build (build number: ) App min and target version: @@ -49,6 +50,7 @@ App min and target version: - [ ] April 2018 Update (17134) - [ ] October 2018 Update (17763) - [ ] May 2019 Update (18362) +- [ ] November 2019 Update (18363) - [ ] Insider Build (xxxxx) Device form factor: diff --git a/Directory.Build.props b/Directory.Build.props index 4f6d23454b8..f432e3aa803 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -15,7 +15,7 @@ $(MSBuildProjectName.Contains('Test')) $(MSBuildProjectName.Contains('Uwp')) $(MSBuildProjectName.Contains('Sample')) - 17763 + 18362 16299 $(MSBuildThisFileDirectory)bin\nupkg diff --git a/GazeInputTest/GazeInputTest.csproj b/GazeInputTest/GazeInputTest.csproj index a5a648e7b9b..31a82625a8f 100644 --- a/GazeInputTest/GazeInputTest.csproj +++ b/GazeInputTest/GazeInputTest.csproj @@ -11,7 +11,7 @@ GazeInputTest en-US UAP - 10.0.17763.0 + 10.0.18362.0 10.0.17134.0 14 512 diff --git a/Microsoft.Toolkit.Uwp.Input.GazeInteraction/Microsoft.Toolkit.UWP.Input.GazeInteraction.vcxproj b/Microsoft.Toolkit.Uwp.Input.GazeInteraction/Microsoft.Toolkit.UWP.Input.GazeInteraction.vcxproj index 74113867050..546b99e33e6 100644 --- a/Microsoft.Toolkit.Uwp.Input.GazeInteraction/Microsoft.Toolkit.UWP.Input.GazeInteraction.vcxproj +++ b/Microsoft.Toolkit.Uwp.Input.GazeInteraction/Microsoft.Toolkit.UWP.Input.GazeInteraction.vcxproj @@ -42,7 +42,7 @@ 14.0 true Windows Store - 10.0.17763.0 + 10.0.18362.0 10.0.17134.0 10.0 Microsoft.Toolkit.Uwp.Input.GazeInteraction diff --git a/Microsoft.Toolkit.Uwp.Notifications/Microsoft.Toolkit.Uwp.Notifications.csproj b/Microsoft.Toolkit.Uwp.Notifications/Microsoft.Toolkit.Uwp.Notifications.csproj index 0b2cf702e3a..d239fc15c33 100644 --- a/Microsoft.Toolkit.Uwp.Notifications/Microsoft.Toolkit.Uwp.Notifications.csproj +++ b/Microsoft.Toolkit.Uwp.Notifications/Microsoft.Toolkit.Uwp.Notifications.csproj @@ -48,7 +48,7 @@ native UAP,Version=v10.0 uap10.0 - 10.0.17763.0 + 10.0.18362.0 10.0.10240.0 $(DefineConstants);NETFX_CORE;WINDOWS_UWP;WINRT false diff --git a/Microsoft.Toolkit.Uwp.SampleApp/Microsoft.Toolkit.Uwp.SampleApp.csproj b/Microsoft.Toolkit.Uwp.SampleApp/Microsoft.Toolkit.Uwp.SampleApp.csproj index d95e24c902f..00f2935b1f9 100644 --- a/Microsoft.Toolkit.Uwp.SampleApp/Microsoft.Toolkit.Uwp.SampleApp.csproj +++ b/Microsoft.Toolkit.Uwp.SampleApp/Microsoft.Toolkit.Uwp.SampleApp.csproj @@ -125,7 +125,7 @@ 6.1.0-build.6 - 2.2.190917002 + 2.3.200213001 0.7.0-alpha diff --git a/Microsoft.Toolkit.Uwp.Samples.BackgroundTasks/Microsoft.Toolkit.Uwp.Samples.BackgroundTasks.csproj b/Microsoft.Toolkit.Uwp.Samples.BackgroundTasks/Microsoft.Toolkit.Uwp.Samples.BackgroundTasks.csproj index 22790daed6c..6782c958335 100644 --- a/Microsoft.Toolkit.Uwp.Samples.BackgroundTasks/Microsoft.Toolkit.Uwp.Samples.BackgroundTasks.csproj +++ b/Microsoft.Toolkit.Uwp.Samples.BackgroundTasks/Microsoft.Toolkit.Uwp.Samples.BackgroundTasks.csproj @@ -11,7 +11,7 @@ Microsoft.Toolkit.Uwp.Samples.BackgroundTasks fr-FR UAP - 10.0.17763.0 + 10.0.18362.0 10.0.16299.0 14 512 diff --git a/Microsoft.Toolkit.Uwp.UI.Controls.DataGrid.Design/Microsoft.Toolkit.Uwp.UI.Controls.DataGrid.Design.csproj b/Microsoft.Toolkit.Uwp.UI.Controls.DataGrid.Design/Microsoft.Toolkit.Uwp.UI.Controls.DataGrid.Design.csproj index 2250fc69b2f..8b1e005e419 100644 --- a/Microsoft.Toolkit.Uwp.UI.Controls.DataGrid.Design/Microsoft.Toolkit.Uwp.UI.Controls.DataGrid.Design.csproj +++ b/Microsoft.Toolkit.Uwp.UI.Controls.DataGrid.Design/Microsoft.Toolkit.Uwp.UI.Controls.DataGrid.Design.csproj @@ -57,7 +57,7 @@ False - $(MSBuildProgramFiles32)\Windows Kits\10\UnionMetadata\10.0.17763.0\Windows.winmd + $(MSBuildProgramFiles32)\Windows Kits\10\UnionMetadata\10.0.18362.0\Windows.winmd @@ -73,12 +73,12 @@ - $(ProgramFiles)\Windows Kits\10\References\10.0.17763.0\Windows.Foundation.FoundationContract\3.0.0.0\Windows.Foundation.FoundationContract.winmd + $(ProgramFiles)\Windows Kits\10\References\10.0.18362.0\Windows.Foundation.FoundationContract\3.0.0.0\Windows.Foundation.FoundationContract.winmd WindowsRuntime False - $(ProgramFiles)\Windows Kits\10\References\10.0.17763.0\Windows.Foundation.UniversalApiContract\7.0.0.0\Windows.Foundation.UniversalApiContract.winmd + $(ProgramFiles)\Windows Kits\10\References\10.0.18362.0\Windows.Foundation.UniversalApiContract\7.0.0.0\Windows.Foundation.UniversalApiContract.winmd WindowsRuntime False diff --git a/Microsoft.Toolkit.Uwp.UI.Controls.Design/Microsoft.Toolkit.Uwp.UI.Controls.Design.csproj b/Microsoft.Toolkit.Uwp.UI.Controls.Design/Microsoft.Toolkit.Uwp.UI.Controls.Design.csproj index b611399dd13..864c02a44b1 100644 --- a/Microsoft.Toolkit.Uwp.UI.Controls.Design/Microsoft.Toolkit.Uwp.UI.Controls.Design.csproj +++ b/Microsoft.Toolkit.Uwp.UI.Controls.Design/Microsoft.Toolkit.Uwp.UI.Controls.Design.csproj @@ -58,7 +58,7 @@ False - $(MSBuildProgramFiles32)\Windows Kits\10\UnionMetadata\10.0.17763.0\Windows.winmd + $(MSBuildProgramFiles32)\Windows Kits\10\UnionMetadata\10.0.18362.0\Windows.winmd @@ -74,12 +74,12 @@ - $(ProgramFiles)\Windows Kits\10\References\10.0.17763.0\Windows.Foundation.FoundationContract\3.0.0.0\Windows.Foundation.FoundationContract.winmd + $(ProgramFiles)\Windows Kits\10\References\10.0.18362.0\Windows.Foundation.FoundationContract\3.0.0.0\Windows.Foundation.FoundationContract.winmd WindowsRuntime False - $(ProgramFiles)\Windows Kits\10\References\10.0.17763.0\Windows.Foundation.UniversalApiContract\7.0.0.0\Windows.Foundation.UniversalApiContract.winmd + $(ProgramFiles)\Windows Kits\10\References\10.0.18362.0\Windows.Foundation.UniversalApiContract\7.0.0.0\Windows.Foundation.UniversalApiContract.winmd WindowsRuntime False diff --git a/Microsoft.Toolkit.Uwp.UI.Controls/MasterDetailsView/BackButtonBehavior.cs b/Microsoft.Toolkit.Uwp.UI.Controls/MasterDetailsView/BackButtonBehavior.cs index 694979e659d..af10e07c1b2 100644 --- a/Microsoft.Toolkit.Uwp.UI.Controls/MasterDetailsView/BackButtonBehavior.cs +++ b/Microsoft.Toolkit.Uwp.UI.Controls/MasterDetailsView/BackButtonBehavior.cs @@ -14,7 +14,7 @@ public enum BackButtonBehavior /// /// /// If the back button controlled by is already visible, the will hook into that button. - /// If the new NavigationView provided by the Windows UI nuget package is used, the will enable and show that button. + /// If the new NavigationView provided by the Windows UI NuGet package is used, the will enable and show that button. /// Otherwise the inline button is used. /// Automatic, diff --git a/Microsoft.Toolkit.Uwp.UI.Controls/MasterDetailsView/MasterDetailsView.BackButton.cs b/Microsoft.Toolkit.Uwp.UI.Controls/MasterDetailsView/MasterDetailsView.BackButton.cs new file mode 100644 index 00000000000..8be46587f61 --- /dev/null +++ b/Microsoft.Toolkit.Uwp.UI.Controls/MasterDetailsView/MasterDetailsView.BackButton.cs @@ -0,0 +1,166 @@ +// 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 System.Reflection; +using Windows.ApplicationModel; +using Windows.UI.Core; +using Windows.UI.Xaml; +using Windows.UI.Xaml.Controls; +using Windows.UI.Xaml.Navigation; + +namespace Microsoft.Toolkit.Uwp.UI.Controls +{ + /// + /// Panel that allows for a Master/Details pattern. + /// + /// + public partial class MasterDetailsView + { + private AppViewBackButtonVisibility? _previousSystemBackButtonVisibility; + private bool _previousNavigationViewBackEnabled; + + // Int used because the underlying type is an enum, but we don't have access to the enum + private int _previousNavigationViewBackVisibilty; + private Button _inlineBackButton; + private object _navigationView; + private Frame _frame; + + /// + /// Sets the back button visibility based on the current visual state and selected item + /// + private void SetBackButtonVisibility(MasterDetailsViewState? previousState = null) + { + const int backButtonVisible = 1; + + if (DesignMode.DesignModeEnabled) + { + return; + } + + if (ViewState == MasterDetailsViewState.Details) + { + if ((BackButtonBehavior == BackButtonBehavior.Inline) && (_inlineBackButton != null)) + { + _inlineBackButton.Visibility = Visibility.Visible; + } + else if (BackButtonBehavior == BackButtonBehavior.Automatic) + { + // Continue to support the system back button if it is being used + SystemNavigationManager navigationManager = SystemNavigationManager.GetForCurrentView(); + if (navigationManager.AppViewBackButtonVisibility == AppViewBackButtonVisibility.Visible) + { + // Setting this indicates that the system back button is being used + _previousSystemBackButtonVisibility = navigationManager.AppViewBackButtonVisibility; + } + else if ((_inlineBackButton != null) && ((_navigationView == null) || (_frame == null))) + { + // We can only use the new NavigationView if we also have a Frame + // If there is no frame we have to use the inline button + _inlineBackButton.Visibility = Visibility.Visible; + } + else + { + SetNavigationViewBackButtonState(backButtonVisible, true); + } + } + else if (BackButtonBehavior != BackButtonBehavior.Manual) + { + SystemNavigationManager navigationManager = SystemNavigationManager.GetForCurrentView(); + _previousSystemBackButtonVisibility = navigationManager.AppViewBackButtonVisibility; + + navigationManager.AppViewBackButtonVisibility = AppViewBackButtonVisibility.Visible; + } + } + else if (previousState == MasterDetailsViewState.Details) + { + if ((BackButtonBehavior == BackButtonBehavior.Inline) && (_inlineBackButton != null)) + { + _inlineBackButton.Visibility = Visibility.Collapsed; + } + else if (BackButtonBehavior == BackButtonBehavior.Automatic) + { + if (!_previousSystemBackButtonVisibility.HasValue) + { + if ((_inlineBackButton != null) && ((_navigationView == null) || (_frame == null))) + { + _inlineBackButton.Visibility = Visibility.Collapsed; + } + else + { + SetNavigationViewBackButtonState(_previousNavigationViewBackVisibilty, _previousNavigationViewBackEnabled); + } + } + } + + if (_previousSystemBackButtonVisibility.HasValue) + { + // Make sure we show the back button if the stack can navigate back + SystemNavigationManager.GetForCurrentView().AppViewBackButtonVisibility = _previousSystemBackButtonVisibility.Value; + _previousSystemBackButtonVisibility = null; + } + } + } + + private void SetNavigationViewBackButtonState(int visible, bool enabled) + { + if (_navigationView == null) + { + return; + } + + System.Type navType = _navigationView.GetType(); + PropertyInfo visibleProperty = navType.GetProperty("IsBackButtonVisible"); + if (visibleProperty != null) + { + _previousNavigationViewBackVisibilty = (int)visibleProperty.GetValue(_navigationView); + visibleProperty.SetValue(_navigationView, visible); + } + + PropertyInfo enabledProperty = navType.GetProperty("IsBackEnabled"); + if (enabledProperty != null) + { + _previousNavigationViewBackEnabled = (bool)enabledProperty.GetValue(_navigationView); + enabledProperty.SetValue(_navigationView, enabled); + } + } + + /// + /// Closes the details pane if we are in narrow state + /// + /// The sender + /// The event args + private void OnFrameNavigating(object sender, NavigatingCancelEventArgs args) + { + if ((args.NavigationMode == NavigationMode.Back) && (ViewState == MasterDetailsViewState.Details)) + { + ClearSelectedItem(); + args.Cancel = true; + } + } + + /// + /// Closes the details pane if we are in narrow state + /// + /// The sender + /// The event args + private void OnBackRequested(object sender, BackRequestedEventArgs args) + { + if (ViewState == MasterDetailsViewState.Details) + { + // let the OnFrameNavigating method handle it if + if (_frame == null || !_frame.CanGoBack) + { + ClearSelectedItem(); + } + + args.Handled = true; + } + } + + private void OnInlineBackButtonClicked(object sender, RoutedEventArgs e) + { + ClearSelectedItem(); + } + } +} diff --git a/Microsoft.Toolkit.Uwp.UI.Controls/MasterDetailsView/MasterDetailsView.Events.cs b/Microsoft.Toolkit.Uwp.UI.Controls/MasterDetailsView/MasterDetailsView.Events.cs index ab7c55a2b29..5caa612b583 100644 --- a/Microsoft.Toolkit.Uwp.UI.Controls/MasterDetailsView/MasterDetailsView.Events.cs +++ b/Microsoft.Toolkit.Uwp.UI.Controls/MasterDetailsView/MasterDetailsView.Events.cs @@ -1,4 +1,4 @@ -// Licensed to the .NET Foundation under one or more agreements. +// 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. @@ -19,7 +19,7 @@ public partial class MasterDetailsView public event SelectionChangedEventHandler SelectionChanged; /// - /// Occurs when the view state changes + /// Occurs when the view state changes. /// public event EventHandler ViewStateChanged; diff --git a/Microsoft.Toolkit.Uwp.UI.Controls/MasterDetailsView/MasterDetailsView.Properties.cs b/Microsoft.Toolkit.Uwp.UI.Controls/MasterDetailsView/MasterDetailsView.Properties.cs index 22f54003331..76184535f3c 100644 --- a/Microsoft.Toolkit.Uwp.UI.Controls/MasterDetailsView/MasterDetailsView.Properties.cs +++ b/Microsoft.Toolkit.Uwp.UI.Controls/MasterDetailsView/MasterDetailsView.Properties.cs @@ -1,4 +1,4 @@ -// Licensed to the .NET Foundation under one or more agreements. +// 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. @@ -53,7 +53,7 @@ public partial class MasterDetailsView nameof(MasterHeader), typeof(object), typeof(MasterDetailsView), - new PropertyMetadata(null, OnMasterHeaderChanged)); + new PropertyMetadata(null)); /// /// Identifies the dependency property. @@ -85,15 +85,46 @@ public partial class MasterDetailsView typeof(MasterDetailsView), new PropertyMetadata(null)); + + /// + /// Identifies the dependency property. + /// + /// The identifier for the dependency property. + public static readonly DependencyProperty DetailsPaneBackgroundProperty = DependencyProperty.Register( + nameof(DetailsPaneBackground), + typeof(Brush), + typeof(MasterDetailsView), + new PropertyMetadata(null)); + + /// + /// Identifies the dependency property. + /// + /// The identifier for the dependency property. + public static readonly DependencyProperty MasterNoItemsContentProperty = DependencyProperty.Register( + nameof(MasterNoItemsContent), + typeof(object), + typeof(MasterDetailsView), + new PropertyMetadata(null)); + + /// + /// Identifies the dependency property. + /// + /// The identifier for the dependency property. + public static readonly DependencyProperty MasterNoItemsContentTemplateProperty = DependencyProperty.Register( + nameof(MasterNoItemsContentTemplate), + typeof(DataTemplate), + typeof(MasterDetailsView), + new PropertyMetadata(null)); + /// /// Identifies the dependency property. /// /// The identifier for the dependency property. public static readonly DependencyProperty MasterPaneWidthProperty = DependencyProperty.Register( nameof(MasterPaneWidth), - typeof(double), + typeof(GridLength), typeof(MasterDetailsView), - new PropertyMetadata(320d)); + new PropertyMetadata(new GridLength(320))); /// /// Identifies the dependency property. @@ -116,7 +147,7 @@ public partial class MasterDetailsView new PropertyMetadata(null)); /// - /// Identifies the dependency property + /// Identifies the dependency property. /// /// The identifier for the dependency property. public static readonly DependencyProperty ViewStateProperty = DependencyProperty.Register( @@ -126,7 +157,7 @@ public partial class MasterDetailsView new PropertyMetadata(default(MasterDetailsViewState))); /// - /// Identifies the dependency property + /// Identifies the dependency property. /// /// The identifier for the dependency property. public static readonly DependencyProperty MasterCommandBarProperty = DependencyProperty.Register( @@ -136,7 +167,7 @@ public partial class MasterDetailsView new PropertyMetadata(null, OnMasterCommandBarChanged)); /// - /// Identifies the dependency property + /// Identifies the dependency property. /// /// The identifier for the dependency property. public static readonly DependencyProperty DetailsCommandBarProperty = DependencyProperty.Register( @@ -146,22 +177,44 @@ public partial class MasterDetailsView new PropertyMetadata(null, OnDetailsCommandBarChanged)); /// - /// Identifies the dependency property + /// Identifies the dependency property. /// + /// The identifier for the dependency property. public static readonly DependencyProperty CompactModeThresholdWidthProperty = DependencyProperty.Register( nameof(CompactModeThresholdWidth), typeof(double), typeof(MasterDetailsView), - new PropertyMetadata(720d, OnCompactModeThresholdWidthChanged)); + new PropertyMetadata(640d)); /// - /// Identifies the dependency property + /// Identifies the dependency property. /// + /// The identifier for the dependency property. public static readonly DependencyProperty BackButtonBehaviorProperty = DependencyProperty.Register( nameof(BackButtonBehavior), typeof(BackButtonBehavior), typeof(MasterDetailsView), - new PropertyMetadata(BackButtonBehavior.System, OnBackButtonBehaviorChanged)); + new PropertyMetadata(null, OnBackButtonBehaviorChanged)); + + /// + /// Identifies the dependency property. + /// + /// The identifier for the dependency property. + public static readonly DependencyProperty DetailsContentTemplateSelectorProperty = DependencyProperty.Register( + nameof(DetailsContentTemplateSelector), + typeof(DataTemplateSelector), + typeof(MasterDetailsView), + new PropertyMetadata(null)); + + /// + /// Identifies the dependency property. + /// + /// The identifier for the dependency property. + public static readonly DependencyProperty MasterItemTemplateSelectorProperty = DependencyProperty.Register( + nameof(MasterItemTemplateSelector), + typeof(DataTemplateSelector), + typeof(MasterDetailsView), + new PropertyMetadata(null)); /// /// Gets or sets the selected item. @@ -193,7 +246,41 @@ public Brush MasterPaneBackground } /// - /// Gets or sets the content for the master pane's header + /// Gets or sets the Brush to apply to the background of the details area of the control. + /// + /// The Brush to apply to the background of the details area of the control. + public Brush DetailsPaneBackground + { + get { return (Brush)GetValue(DetailsPaneBackgroundProperty); } + set { SetValue(DetailsPaneBackgroundProperty, value); } + } + + /// + /// Gets or sets the content for the master pane's no items presenter. + /// + /// + /// The content of the master pane's header. The default is null. + /// + public object MasterNoItemsContent + { + get { return GetValue(MasterNoItemsContentProperty); } + set { SetValue(MasterNoItemsContentProperty, value); } + } + + /// + /// Gets or sets the DataTemplate used to display the master pane's no items presenter. + /// + /// + /// The template that specifies the visualization of the master pane no items object. The default is null. + /// + public DataTemplate MasterNoItemsContentTemplate + { + get { return (DataTemplate)GetValue(MasterNoItemsContentTemplateProperty); } + set { SetValue(MasterNoItemsContentTemplateProperty, value); } + } + + /// + /// Gets or sets the content for the master pane's header. /// /// /// The content of the master pane's header. The default is null. @@ -247,14 +334,14 @@ public DataTemplate DetailsHeaderTemplate /// The width of the SplitView pane when it's fully expanded. The default is 320 /// device-independent pixel (DIP). /// - public double MasterPaneWidth + public GridLength MasterPaneWidth { - get { return (double)GetValue(MasterPaneWidthProperty); } + get { return (GridLength)GetValue(MasterPaneWidthProperty); } set { SetValue(MasterPaneWidthProperty, value); } } /// - /// Gets or sets the content to dsiplay when there is no item selected in the master list. + /// Gets or sets the content to display when there is no item selected in the master list. /// public object NoSelectionContent { @@ -276,12 +363,12 @@ public DataTemplate NoSelectionContentTemplate } /// - /// Gets the current visual state of the control + /// Gets or sets gets the current visual state of the control. /// public MasterDetailsViewState ViewState { get { return (MasterDetailsViewState)GetValue(ViewStateProperty); } - private set { SetValue(ViewStateProperty, value); } + set { SetValue(ViewStateProperty, value); } } /// @@ -303,7 +390,7 @@ public CommandBar DetailsCommandBar } /// - /// Gets or sets the Threshold width that witll trigger the control to go into compact mode + /// Gets or sets the Threshold width that will trigger the control to go into compact mode. /// public double CompactModeThresholdWidth { @@ -312,7 +399,7 @@ public double CompactModeThresholdWidth } /// - /// Gets or sets the behavior to use for the back button + /// Gets or sets the behavior to use for the back button. /// /// The current BackButtonBehavior. The default is System. public BackButtonBehavior BackButtonBehavior @@ -321,10 +408,48 @@ public BackButtonBehavior BackButtonBehavior set { SetValue(BackButtonBehaviorProperty, value); } } + /// + /// Gets or sets the for the details presenter. + /// + public DataTemplateSelector DetailsContentTemplateSelector + { + get { return (DataTemplateSelector)GetValue(DetailsContentTemplateSelectorProperty); } + set { SetValue(DetailsContentTemplateSelectorProperty, value); } + } + + /// + /// Gets or sets the for the master list items. + /// + public DataTemplateSelector MasterItemTemplateSelector + { + get { return (DataTemplateSelector)GetValue(MasterItemTemplateSelectorProperty); } + set { SetValue(MasterItemTemplateSelectorProperty, value); } + } + /// /// Gets or sets a function for mapping the selected item to a different model. /// This new model will be the DataContext of the Details area. /// public Func MapDetails { get; set; } + + private static void OnDetailsCommandBarChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + ((MasterDetailsView)d).OnDetailsCommandBarChanged(); + } + + private static void OnMasterCommandBarChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + ((MasterDetailsView)d).OnMasterCommandBarChanged(); + } + + private static void OnSelectedItemChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + ((MasterDetailsView)d).OnSelectedItemChanged(e); + } + + private static void OnBackButtonBehaviorChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + ((MasterDetailsView)d).SetBackButtonVisibility(); + } } } diff --git a/Microsoft.Toolkit.Uwp.UI.Controls/MasterDetailsView/MasterDetailsView.cs b/Microsoft.Toolkit.Uwp.UI.Controls/MasterDetailsView/MasterDetailsView.cs index 62e654d5300..6fea5ed6dda 100644 --- a/Microsoft.Toolkit.Uwp.UI.Controls/MasterDetailsView/MasterDetailsView.cs +++ b/Microsoft.Toolkit.Uwp.UI.Controls/MasterDetailsView/MasterDetailsView.cs @@ -1,4 +1,4 @@ -// Licensed to the .NET Foundation under one or more agreements. +// 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. @@ -10,7 +10,6 @@ using Windows.UI.Xaml; using Windows.UI.Xaml.Controls; using Windows.UI.Xaml.Input; -using Windows.UI.Xaml.Navigation; namespace Microsoft.Toolkit.Uwp.UI.Controls { @@ -23,33 +22,37 @@ namespace Microsoft.Toolkit.Uwp.UI.Controls [TemplateVisualState(Name = NoSelectionWideState, GroupName = SelectionStates)] [TemplateVisualState(Name = HasSelectionWideState, GroupName = SelectionStates)] [TemplateVisualState(Name = HasSelectionNarrowState, GroupName = SelectionStates)] - [TemplateVisualState(Name = NarrowState, GroupName = WidthStates)] - [TemplateVisualState(Name = WideState, GroupName = WidthStates)] public partial class MasterDetailsView : ItemsControl { + // All view states: + private const string SelectionStates = "SelectionStates"; + private const string NoSelectionWideState = "NoSelectionWide"; + private const string HasSelectionWideState = "HasSelectionWide"; + private const string NoSelectionNarrowState = "NoSelectionNarrow"; + private const string HasSelectionNarrowState = "HasSelectionNarrow"; + + private const string HasItemsStates = "HasItemsStates"; + private const string HasItemsState = "HasItemsState"; + private const string HasNoItemsState = "HasNoItemsState"; + + // Control names: + private const string PartRootPanel = "RootPanel"; private const string PartDetailsPresenter = "DetailsPresenter"; private const string PartDetailsPanel = "DetailsPanel"; + private const string PartMasterList = "MasterList"; private const string PartBackButton = "MasterDetailsBackButton"; private const string PartHeaderContentPresenter = "HeaderContentPresenter"; - private const string NarrowState = "NarrowState"; - private const string WideState = "WideState"; - private const string WidthStates = "WidthStates"; - private const string SelectionStates = "SelectionStates"; - private const string HasSelectionNarrowState = "HasSelectionNarrow"; - private const string HasSelectionWideState = "HasSelectionWide"; - private const string NoSelectionNarrowState = "NoSelectionNarrow"; - private const string NoSelectionWideState = "NoSelectionWide"; + private const string PartMasterCommandBarPanel = "MasterCommandBarPanel"; + private const string PartDetailsCommandBarPanel = "DetailsCommandBarPanel"; - private AppViewBackButtonVisibility? _previousSystemBackButtonVisibility; - private bool _previousNavigationViewBackEnabled; + /// + /// Used to prevent screen flickering if only the order of the selected item changed. + /// + private bool _ignoreClearSelectedItem; - // Int used because the underlying type is an enum, but we don't have access to the enum - private int _previousNavigationViewBackVisibilty; private ContentPresenter _detailsPresenter; + private Microsoft.UI.Xaml.Controls.TwoPaneView _twoPaneView; private VisualStateGroup _selectionStateGroup; - private Button _inlineBackButton; - private object _navigationView; - private Frame _frame; /// /// Initializes a new instance of the class. @@ -63,217 +66,107 @@ public MasterDetailsView() } /// - /// Invoked whenever application code or internal processes (such as a rebuilding layout pass) call - /// ApplyTemplate. In simplest terms, this means the method is called just before a UI element displays - /// in your app. Override this method to influence the default post-template logic of a class. + /// Updates the visual state of the control. /// - protected override void OnApplyTemplate() + /// False to skip animations. + private void SetVisualState(bool animate) { - base.OnApplyTemplate(); - - if (_inlineBackButton != null) + string noSelectionState; + string hasSelectionState; + if (ViewState == MasterDetailsViewState.Both) { - _inlineBackButton.Click -= OnInlineBackButtonClicked; + noSelectionState = NoSelectionWideState; + hasSelectionState = HasSelectionWideState; } - - _inlineBackButton = (Button)GetTemplateChild(PartBackButton); - if (_inlineBackButton != null) + else { - _inlineBackButton.Click += OnInlineBackButtonClicked; + noSelectionState = NoSelectionNarrowState; + hasSelectionState = HasSelectionNarrowState; } - _detailsPresenter = (ContentPresenter)GetTemplateChild(PartDetailsPresenter); - SetDetailsContent(); - - SetMasterHeaderVisibility(); - OnDetailsCommandBarChanged(); - OnMasterCommandBarChanged(); - - SizeChanged -= MasterDetailsView_SizeChanged; - SizeChanged += MasterDetailsView_SizeChanged; - - UpdateView(true); + VisualStateManager.GoToState(this, SelectedItem == null ? noSelectionState : hasSelectionState, animate); + VisualStateManager.GoToState(this, Items.Count > 0 ? HasItemsState : HasNoItemsState, animate); } /// - /// Fired when the SelectedItem changes. + /// Sets the content of the based on current function. /// - /// The sender - /// The event args - /// - /// Sets up animations for the DetailsPresenter for animating in/out. - /// - private static void OnSelectedItemChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + private void SetDetailsContent() { - var view = (MasterDetailsView)d; - - view.OnSelectionChanged(new SelectionChangedEventArgs(new List { e.OldValue }, new List { e.NewValue })); - - view.UpdateView(true); - - // If there is no selection, do not remove the DetailsPresenter content but let it animate out. - if (view.SelectedItem != null) + if (_detailsPresenter != null) { - view.SetDetailsContent(); - } - } - - /// - /// Fired when the is changed. - /// - /// The sender - /// The event args - private static void OnMasterHeaderChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - var view = (MasterDetailsView)d; - view.SetMasterHeaderVisibility(); - } - - /// - /// Fired when the DetailsCommandBar changes. - /// - /// The sender - /// The event args - private static void OnDetailsCommandBarChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - var view = (MasterDetailsView)d; - view.OnDetailsCommandBarChanged(); - } + // Update the content template: + if (_detailsPresenter.ContentTemplateSelector != null) + { + _detailsPresenter.ContentTemplate = _detailsPresenter.ContentTemplateSelector.SelectTemplate(SelectedItem, _detailsPresenter); + } - /// - /// Fired when CompactModeThresholdWIdthChanged - /// - /// The sender - /// The event args - private static void OnCompactModeThresholdWidthChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - ((MasterDetailsView)d).HandleStateChanges(); + // Update the content: + _detailsPresenter.Content = MapDetails == null + ? SelectedItem + : SelectedItem != null ? MapDetails(SelectedItem) : null; + } } - private static void OnBackButtonBehaviorChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + private void SetMasterHeaderVisibility() { - var view = (MasterDetailsView)d; - view.SetBackButtonVisibility(); + if (GetTemplateChild(PartHeaderContentPresenter) is FrameworkElement headerPresenter) + { + headerPresenter.Visibility = MasterHeader != null + ? Visibility.Visible + : Visibility.Collapsed; + } } /// - /// Fired when the MasterCommandBar changes. + /// Clears the and prevent flickering of the UI if only the order of the items changed. /// - /// The sender - /// The event args - private static void OnMasterCommandBarChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - var view = (MasterDetailsView)d; - view.OnMasterCommandBarChanged(); - } - - private void OnLoaded(object sender, RoutedEventArgs e) + public void ClearSelectedItem() { - if (DesignMode.DesignModeEnabled == false) - { - SystemNavigationManager.GetForCurrentView().BackRequested += OnBackRequested; - if (_frame != null) - { - _frame.Navigating -= OnFrameNavigating; - } - - _navigationView = this.FindAscendants().FirstOrDefault(p => p.GetType().FullName == "Microsoft.UI.Xaml.Controls.NavigationView"); - _frame = this.FindAscendant(); - if (_frame != null) - { - _frame.Navigating += OnFrameNavigating; - } - - _selectionStateGroup = (VisualStateGroup)GetTemplateChild(SelectionStates); - if (_selectionStateGroup != null) - { - _selectionStateGroup.CurrentStateChanged += OnSelectionStateChanged; - } - - UpdateView(true); - } + _ignoreClearSelectedItem = true; + SelectedItem = null; + _ignoreClearSelectedItem = false; } - private void OnUnloaded(object sender, RoutedEventArgs e) + private void OnCommandBarChanged(string panelName, CommandBar commandbar) { - if (DesignMode.DesignModeEnabled == false) + if (GetTemplateChild(panelName) is Panel panel) { - SystemNavigationManager.GetForCurrentView().BackRequested -= OnBackRequested; - if (_frame != null) + panel.Children.Clear(); + if (commandbar != null) { - _frame.Navigating -= OnFrameNavigating; + panel.Children.Add(commandbar); } - - _selectionStateGroup = (VisualStateGroup)GetTemplateChild(SelectionStates); - if (_selectionStateGroup != null) - { - _selectionStateGroup.CurrentStateChanged -= OnSelectionStateChanged; - _selectionStateGroup = null; - } - } - } - - private void MasterDetailsView_SizeChanged(object sender, SizeChangedEventArgs e) - { - // if size is changing - if ((e.PreviousSize.Width < CompactModeThresholdWidth && e.NewSize.Width >= CompactModeThresholdWidth) || - (e.PreviousSize.Width >= CompactModeThresholdWidth && e.NewSize.Width < CompactModeThresholdWidth)) - { - HandleStateChanges(); } } - private void OnInlineBackButtonClicked(object sender, RoutedEventArgs e) + private void OnMasterCommandBarChanged() { - SelectedItem = null; + OnCommandBarChanged(PartMasterCommandBarPanel, MasterCommandBar); } - private void HandleStateChanges() + private void OnDetailsCommandBarChanged() { - UpdateView(true); - SetListSelectionWithKeyboardFocusOnVisualStateChanged(ViewState); + OnCommandBarChanged(PartDetailsCommandBarPanel, DetailsCommandBar); } - /// - /// Closes the details pane if we are in narrow state - /// - /// The sender - /// The event args - private void OnFrameNavigating(object sender, NavigatingCancelEventArgs args) + private void OnSelectedItemChanged(DependencyPropertyChangedEventArgs e) { - if ((args.NavigationMode == NavigationMode.Back) && (ViewState == MasterDetailsViewState.Details)) + // Prevent setting the SelectedItem to null if only the order changed (=> collection reset got triggered). + if (!_ignoreClearSelectedItem && e.OldValue != null && e.NewValue == null && Items.Contains(e.OldValue)) { - SelectedItem = null; - args.Cancel = true; + SelectedItem = e.OldValue; + return; } - } - /// - /// Closes the details pane if we are in narrow state - /// - /// The sender - /// The event args - private void OnBackRequested(object sender, BackRequestedEventArgs args) - { - if (ViewState == MasterDetailsViewState.Details) - { - // let the OnFrameNavigating method handle it if - if (_frame == null || !_frame.CanGoBack) - { - SelectedItem = null; - } + OnSelectionChanged(new SelectionChangedEventArgs(new List { e.OldValue }, new List { e.NewValue })); - args.Handled = true; - } - } + UpdateView(true); - private void SetMasterHeaderVisibility() - { - if (GetTemplateChild(PartHeaderContentPresenter) is FrameworkElement headerPresenter) + // If there is no selection, do not remove the DetailsPresenter content but let it animate out. + if (SelectedItem != null) { - headerPresenter.Visibility = MasterHeader != null - ? Visibility.Visible - : Visibility.Collapsed; + SetDetailsContent(); } } @@ -283,90 +176,23 @@ private void UpdateView(bool animate) SetVisualState(animate); } - /// - /// Sets the back button visibility based on the current visual state and selected item - /// - private void SetBackButtonVisibility(MasterDetailsViewState? previousState = null) + private void UpdateViewState() { - const int backButtonVisible = 1; + MasterDetailsViewState previousState = ViewState; - if (DesignMode.DesignModeEnabled) + if (_twoPaneView == null) { - return; - } - - if (ViewState == MasterDetailsViewState.Details) - { - if ((BackButtonBehavior == BackButtonBehavior.Inline) && (_inlineBackButton != null)) - { - _inlineBackButton.Visibility = Visibility.Visible; - } - else if (BackButtonBehavior == BackButtonBehavior.Automatic) - { - // Continue to support the system back button if it is being used - var navigationManager = SystemNavigationManager.GetForCurrentView(); - if (navigationManager.AppViewBackButtonVisibility == AppViewBackButtonVisibility.Visible) - { - // Setting this indicates that the system back button is being used - _previousSystemBackButtonVisibility = navigationManager.AppViewBackButtonVisibility; - } - else if ((_inlineBackButton != null) && ((_navigationView == null) || (_frame == null))) - { - // We can only use the new NavigationView if we also have a Frame - // If there is no frame we have to use the inline button - _inlineBackButton.Visibility = Visibility.Visible; - } - else - { - SetNavigationViewBackButtonState(backButtonVisible, true); - } - } - else if (BackButtonBehavior != BackButtonBehavior.Manual) - { - var navigationManager = SystemNavigationManager.GetForCurrentView(); - _previousSystemBackButtonVisibility = navigationManager.AppViewBackButtonVisibility; - - navigationManager.AppViewBackButtonVisibility = AppViewBackButtonVisibility.Visible; - } - } - else if (previousState == MasterDetailsViewState.Details) - { - if ((BackButtonBehavior == BackButtonBehavior.Inline) && (_inlineBackButton != null)) - { - _inlineBackButton.Visibility = Visibility.Collapsed; - } - else if (BackButtonBehavior == BackButtonBehavior.Automatic) - { - if (_previousSystemBackButtonVisibility.HasValue == false) - { - if ((_inlineBackButton != null) && ((_navigationView == null) || (_frame == null))) - { - _inlineBackButton.Visibility = Visibility.Collapsed; - } - else - { - SetNavigationViewBackButtonState(_previousNavigationViewBackVisibilty, _previousNavigationViewBackEnabled); - } - } - } - - if (_previousSystemBackButtonVisibility.HasValue) - { - // Make sure we show the back button if the stack can navigate back - SystemNavigationManager.GetForCurrentView().AppViewBackButtonVisibility = _previousSystemBackButtonVisibility.Value; - _previousSystemBackButtonVisibility = null; - } + ViewState = MasterDetailsViewState.Both; } - } - private void UpdateViewState() - { - var previousState = ViewState; - - if (ActualWidth < CompactModeThresholdWidth) + // Single pane: + else if (_twoPaneView.Mode == Microsoft.UI.Xaml.Controls.TwoPaneViewMode.SinglePane) { ViewState = SelectedItem == null ? MasterDetailsViewState.Master : MasterDetailsViewState.Details; + _twoPaneView.PanePriority = SelectedItem == null ? Microsoft.UI.Xaml.Controls.TwoPaneViewPriority.Pane1 : Microsoft.UI.Xaml.Controls.TwoPaneViewPriority.Pane2; } + + // Dual pane: else { ViewState = MasterDetailsViewState.Both; @@ -379,83 +205,42 @@ private void UpdateViewState() } } - private void SetVisualState(bool animate) + /// + /// Sets focus to the relevant control based on the viewState. + /// + /// the view state + private void SetFocus(MasterDetailsViewState viewState) { - string state; - string noSelectionState; - string hasSelectionState; - if (ActualWidth < CompactModeThresholdWidth) + if (viewState != MasterDetailsViewState.Details) { - state = NarrowState; - noSelectionState = NoSelectionNarrowState; - hasSelectionState = HasSelectionNarrowState; + FocusItemList(); } else { - state = WideState; - noSelectionState = NoSelectionWideState; - hasSelectionState = HasSelectionWideState; - } - - VisualStateManager.GoToState(this, state, animate); - VisualStateManager.GoToState(this, SelectedItem == null ? noSelectionState : hasSelectionState, animate); - } - - private void SetNavigationViewBackButtonState(int visible, bool enabled) - { - if (_navigationView == null) - { - return; - } - - var navType = _navigationView.GetType(); - var visibleProperty = navType.GetProperty("IsBackButtonVisible"); - if (visibleProperty != null) - { - _previousNavigationViewBackVisibilty = (int)visibleProperty.GetValue(_navigationView); - visibleProperty.SetValue(_navigationView, visible); - } - - var enabledProperty = navType.GetProperty("IsBackEnabled"); - if (enabledProperty != null) - { - _previousNavigationViewBackEnabled = (bool)enabledProperty.GetValue(_navigationView); - enabledProperty.SetValue(_navigationView, enabled); + FocusFirstFocusableElementInDetails(); } } - private void SetDetailsContent() + /// + /// Sets focus to the first focusable element in the details template + /// + private void FocusFirstFocusableElementInDetails() { - if (_detailsPresenter != null) + if (GetTemplateChild(PartDetailsPanel) is DependencyObject details) { - _detailsPresenter.Content = MapDetails == null - ? SelectedItem - : SelectedItem != null ? MapDetails(SelectedItem) : null; + DependencyObject focusableElement = FocusManager.FindFirstFocusableElement(details); + (focusableElement as Control)?.Focus(FocusState.Programmatic); } } - private void OnMasterCommandBarChanged() - { - OnCommandBarChanged("MasterCommandBarPanel", MasterCommandBar); - } - - private void OnDetailsCommandBarChanged() - { - OnCommandBarChanged("DetailsCommandBarPanel", DetailsCommandBar); - } - - private void OnCommandBarChanged(string panelName, CommandBar commandbar) + /// + /// Sets focus to the item list + /// + private void FocusItemList() { - var panel = GetTemplateChild(panelName) as Panel; - if (panel == null) - { - return; - } - - panel.Children.Clear(); - if (commandbar != null) + if (GetTemplateChild(PartMasterList) is Control masterList) { - panel.Children.Add(commandbar); + masterList.Focus(FocusState.Programmatic); } } @@ -480,64 +265,120 @@ private void SetListSelectionWithKeyboardFocusOnVisualStateChanged(MasterDetails /// private void SetListSelectionWithKeyboardFocus(bool singleSelectionFollowsFocus) { - if (GetTemplateChild("MasterList") is Windows.UI.Xaml.Controls.ListViewBase masterList) + if (GetTemplateChild(PartMasterCommandBarPanel) is ListViewBase masterList) { masterList.SingleSelectionFollowsFocus = singleSelectionFollowsFocus; } } /// - /// Fires when the selection state of the control changes + /// Invoked once the items changed and ensures the visual state is constant. /// - /// the sender - /// the event args - /// - /// Sets focus to the item list when the viewState is not Details. - /// Sets whether the selected item should change when focused with the keyboard. - /// - private void OnSelectionStateChanged(object sender, VisualStateChangedEventArgs e) + protected override void OnItemsChanged(object e) { - SetFocus(ViewState); - SetListSelectionWithKeyboardFocusOnVisualStateChanged(ViewState); + base.OnItemsChanged(e); + UpdateView(true); } /// - /// Sets focus to the relevant control based on the viewState. + /// Invoked whenever application code or internal processes (such as a rebuilding layout pass) call + /// ApplyTemplate. In simplest terms, this means the method is called just before a UI element displays + /// in your app. Override this method to influence the default post-template logic of a class. /// - /// the view state - private void SetFocus(MasterDetailsViewState viewState) + protected override void OnApplyTemplate() { - if (viewState != MasterDetailsViewState.Details) + base.OnApplyTemplate(); + + if (_inlineBackButton != null) { - FocusItemList(); + _inlineBackButton.Click -= OnInlineBackButtonClicked; } - else + + _inlineBackButton = (Button)GetTemplateChild(PartBackButton); + if (_inlineBackButton != null) { - FocusFirstFocusableElementInDetails(); + _inlineBackButton.Click += OnInlineBackButtonClicked; + } + + _selectionStateGroup = (VisualStateGroup)GetTemplateChild(SelectionStates); + if (_selectionStateGroup != null) + { + _selectionStateGroup.CurrentStateChanged += OnSelectionStateChanged; + } + + _twoPaneView = (Microsoft.UI.Xaml.Controls.TwoPaneView)GetTemplateChild(PartRootPanel); + if (_twoPaneView != null) + { + _twoPaneView.ModeChanged += OnModeChanged; } + + _detailsPresenter = (ContentPresenter)GetTemplateChild(PartDetailsPresenter); + + SetDetailsContent(); + + SetMasterHeaderVisibility(); + OnDetailsCommandBarChanged(); + OnMasterCommandBarChanged(); + + UpdateView(true); } - /// - /// Sets focus to the first focusable element in the details template - /// - private void FocusFirstFocusableElementInDetails() + private void OnUnloaded(object sender, RoutedEventArgs e) { - if (GetTemplateChild(PartDetailsPanel) is DependencyObject details) + if (!DesignMode.DesignModeEnabled) { - var focusableElement = FocusManager.FindFirstFocusableElement(details); - (focusableElement as Control)?.Focus(FocusState.Programmatic); + SystemNavigationManager.GetForCurrentView().BackRequested -= OnBackRequested; + if (_frame != null) + { + _frame.Navigating -= OnFrameNavigating; + } + + _selectionStateGroup = (VisualStateGroup)GetTemplateChild(SelectionStates); + if (_selectionStateGroup != null) + { + _selectionStateGroup.CurrentStateChanged -= OnSelectionStateChanged; + _selectionStateGroup = null; + } } } - /// - /// Sets focus to the item list - /// - private void FocusItemList() + private void OnLoaded(object sender, RoutedEventArgs e) { - if (GetTemplateChild("MasterList") is Control masterList) + if (!DesignMode.DesignModeEnabled) { - masterList.Focus(FocusState.Programmatic); + SystemNavigationManager.GetForCurrentView().BackRequested += OnBackRequested; + if (_frame != null) + { + _frame.Navigating -= OnFrameNavigating; + } + + _navigationView = this.FindAscendants().FirstOrDefault(p => p.GetType().FullName == "Microsoft.UI.Xaml.Controls.NavigationView"); + _frame = this.FindAscendant(); + if (_frame != null) + { + _frame.Navigating += OnFrameNavigating; + } } } + + private void OnModeChanged(Microsoft.UI.Xaml.Controls.TwoPaneView sender, object args) + { + UpdateView(true); + } + + /// + /// Fires when the selection state of the control changes + /// + /// the sender + /// the event args + /// + /// Sets focus to the item list when the viewState is not Details. + /// Sets whether the selected item should change when focused with the keyboard. + /// + private void OnSelectionStateChanged(object sender, VisualStateChangedEventArgs e) + { + SetFocus(ViewState); + SetListSelectionWithKeyboardFocusOnVisualStateChanged(ViewState); + } } -} \ No newline at end of file +} diff --git a/Microsoft.Toolkit.Uwp.UI.Controls/MasterDetailsView/MasterDetailsView.xaml b/Microsoft.Toolkit.Uwp.UI.Controls/MasterDetailsView/MasterDetailsView.xaml index dd37399662f..9ab07cb3fed 100644 --- a/Microsoft.Toolkit.Uwp.UI.Controls/MasterDetailsView/MasterDetailsView.xaml +++ b/Microsoft.Toolkit.Uwp.UI.Controls/MasterDetailsView/MasterDetailsView.xaml @@ -1,6 +1,7 @@  + xmlns:controls="using:Microsoft.Toolkit.Uwp.UI.Controls" + xmlns:muxc="using:Microsoft.UI.Xaml.Controls">