Skip to content

Commit

Permalink
NavigationView BottomMenuItems implementation (microsoft/microsoft-ui…
Browse files Browse the repository at this point in the history
  • Loading branch information
Kinnara committed Aug 20, 2020
1 parent 08209c5 commit f74c8c7
Show file tree
Hide file tree
Showing 16 changed files with 754 additions and 379 deletions.
841 changes: 558 additions & 283 deletions ModernWpf.Controls/NavigationView/NavigationView.cs

Large diffs are not rendered by default.

48 changes: 48 additions & 0 deletions ModernWpf.Controls/NavigationView/NavigationView.properties.cs
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,54 @@ private static void OnExpandedModeThresholdWidthPropertyChanged(DependencyObject

#endregion

#region FooterMenuItems

private static readonly DependencyPropertyKey FooterMenuItemsPropertyKey =
DependencyProperty.RegisterReadOnly(
nameof(FooterMenuItems),
typeof(IList),
typeof(NavigationView),
new PropertyMetadata(OnFooterMenuItemsPropertyChanged));

private static readonly DependencyProperty FooterMenuItemsProperty =
FooterMenuItemsPropertyKey.DependencyProperty;

public IList FooterMenuItems
{
get => (IList)GetValue(FooterMenuItemsProperty);
}

private static void OnFooterMenuItemsPropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs args)
{
var owner = (NavigationView)sender;
owner.PropertyChanged(args);
}

#endregion

#region FooterMenuItemsSource

public static readonly DependencyProperty FooterMenuItemsSourceProperty =
DependencyProperty.Register(
nameof(FooterMenuItemsSource),
typeof(object),
typeof(NavigationView),
new PropertyMetadata(OnFooterMenuItemsSourcePropertyChanged));

public object FooterMenuItemsSource
{
get => GetValue(FooterMenuItemsSourceProperty);
set => SetValue(FooterMenuItemsSourceProperty, value);
}

private static void OnFooterMenuItemsSourcePropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs args)
{
var owner = (NavigationView)sender;
owner.PropertyChanged(args);
}

#endregion

#region PaneFooter

public static readonly DependencyProperty PaneFooterProperty =
Expand Down
100 changes: 40 additions & 60 deletions ModernWpf.Controls/NavigationView/NavigationView.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -888,20 +888,6 @@
</VisualState>
</VisualStateGroup>

<VisualStateGroup x:Name="SettingsGroup">
<VisualState x:Name="SettingsVisible" />
<VisualState x:Name="SettingsCollapsed">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="SettingsNavPaneItem" Storyboard.TargetProperty="Visibility">
<DiscreteObjectKeyFrame KeyTime="0" Value="{x:Static Visibility.Collapsed}" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="SettingsTopNavPaneItem" Storyboard.TargetProperty="Visibility">
<DiscreteObjectKeyFrame KeyTime="0" Value="{x:Static Visibility.Collapsed}" />
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
</VisualStateGroup>

<VisualStateGroup x:Name="AutoSuggestGroup">
<VisualState x:Name="AutoSuggestBoxVisible" />
<VisualState x:Name="AutoSuggestBoxCollapsed">
Expand Down Expand Up @@ -1148,11 +1134,7 @@
<local:ItemsRepeaterScrollHost>
<ScrollViewer VerticalScrollBarVisibility="Auto">
<local:ItemsRepeater
x:Name="TopNavMenuItemsOverflowHost">
<local:ItemsRepeater.Layout>
<local:StackLayout Orientation="Vertical"/>
</local:ItemsRepeater.Layout>
</local:ItemsRepeater>
x:Name="TopNavMenuItemsOverflowHost"/>
</ScrollViewer>
</local:ItemsRepeaterScrollHost>
</local:Flyout>
Expand Down Expand Up @@ -1189,14 +1171,14 @@
VerticalContentAlignment="Stretch"
HorizontalContentAlignment="Stretch"
Grid.Column="7" />
<Grid
Grid.Column="8" >
<local:NavigationViewItem
x:Name="SettingsTopNavPaneItem"
Style="{StaticResource MUX_NavigationViewSettingsItemStyleWhenOnTopPane}"
Icon="Setting"/>

</Grid>
<!-- Top footer menu ItemsRepeater -->
<local:ItemsRepeater
Grid.Column="8"
x:Name="TopFooterMenuItemsHost">
<local:ItemsRepeater.Layout>
<local:StackLayout Orientation="Horizontal"/>
</local:ItemsRepeater.Layout>
</local:ItemsRepeater>

</Grid>
<Border
Expand Down Expand Up @@ -1224,17 +1206,12 @@
Visibility="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=TemplateSettings.LeftPaneVisibility}">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="0"/>
<!-- above button margin + back button space -->
<RowDefinition Height="0"/> <!-- above button margin + back button space -->
<RowDefinition x:Name="PaneContentGridToggleButtonRow" Height="Auto" MinHeight="{DynamicResource NavigationViewPaneHeaderRowMinHeight}"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="8"/>
<!-- above list margin -->
<RowDefinition Height="8"/> <!-- above list margin -->
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="8"/>
</Grid.RowDefinitions>

<Grid x:Name="ContentPaneTopPadding"
Expand Down Expand Up @@ -1289,40 +1266,44 @@
HorizontalContentAlignment="Stretch"
Grid.Row="4" />

<!-- Left nav ItemsRepeater -->
<local:ItemsRepeaterScrollHost
Grid.Row="6"
Margin="0,0,0,20"
HorizontalAlignment="Stretch"
VerticalAlignment="Top">
VerticalAlignment="Stretch">
<ScrollViewer
KeyboardNavigation.TabNavigation="Once"
KeyboardNavigation.TabNavigation="Local"
VerticalScrollBarVisibility="Auto">
<local:ItemsRepeater
<Grid x:Name="ScrollingContentGrid">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="8"/>
</Grid.RowDefinitions>

<!-- Left nav ItemsRepeater -->
<local:ItemsRepeater
x:Name="MenuItemsHost"
AutomationProperties.Name="{TemplateBinding AutomationProperties.Name}">
<local:ItemsRepeater.Layout>
<local:StackLayout Orientation="Vertical"/>
</local:ItemsRepeater.Layout>
</local:ItemsRepeater>
Margin="0,0,0,20"
AutomationProperties.Name="{TemplateBinding AutomationProperties.Name}"/>


<ContentControl
x:Name="FooterContentBorder"
Style="{StaticResource DefaultContentControlStyle}"
IsTabStop="False"
VerticalContentAlignment="Stretch"
HorizontalContentAlignment="Stretch"
Grid.Row="2" />
<!-- Left footer menu ItemsRepeater -->
<local:ItemsRepeater
x:Name="FooterMenuItemsHost"
Grid.Row="3"/>
</Grid>
</ScrollViewer>
</local:ItemsRepeaterScrollHost>


<ContentControl
x:Name="FooterContentBorder"
Style="{StaticResource DefaultContentControlStyle}"
IsTabStop="False"
VerticalContentAlignment="Stretch"
HorizontalContentAlignment="Stretch"
Grid.Row="7" />
<Grid
Grid.Row="8">
<local:NavigationViewItem
x:Name="SettingsNavPaneItem"
Icon="Setting"/>
</Grid>

</Grid>
</local:SplitView.Pane>

Expand Down Expand Up @@ -1381,7 +1362,6 @@

<Trigger SourceName="PaneStateListSizeGroupListener" Property="CurrentStateName" Value="ListSizeCompact">
<Setter TargetName="PaneContentGrid" Property="Width" Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=CompactPaneLength}" />
<Setter TargetName="SettingsNavPaneItem" Property="HorizontalAlignment" Value="Left" />
<Setter TargetName="PaneTitleTextBlock" Property="Visibility" Value="Collapsed" />
<Setter TargetName="PaneHeaderContentBorder" Property="Visibility" Value="Collapsed" />
<Setter TargetName="PaneCustomContentBorder" Property="HorizontalAlignment" Value="Left" />
Expand Down
4 changes: 3 additions & 1 deletion ModernWpf.Controls/NavigationView/NavigationViewHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@ enum NavigationViewRepeaterPosition
{
LeftNav,
TopPrimary,
TopOverflow
TopOverflow,
LeftFooter,
TopFooter
}

enum NavigationViewPropagateTarget
Expand Down
5 changes: 4 additions & 1 deletion ModernWpf.Controls/NavigationView/NavigationViewItem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -343,6 +343,7 @@ void UpdateVisualStateForNavigationViewPositionChange()
switch (position)
{
case NavigationViewRepeaterPosition.LeftNav:
case NavigationViewRepeaterPosition.LeftFooter:
if (SharedHelpers.IsRS4OrHigher() && false /*Application.Current.FocusVisualKind == FocusVisualKind.Reveal*/)
{
// OnLeftNavigationReveal is introduced in RS6.
Expand All @@ -354,6 +355,7 @@ void UpdateVisualStateForNavigationViewPositionChange()
}
break;
case NavigationViewRepeaterPosition.TopPrimary:
case NavigationViewRepeaterPosition.TopFooter:
if (SharedHelpers.IsRS4OrHigher() && false /*Application.Current.FocusVisualKind == FocusVisualKind.Reveal*/)
{
stateName = c_OnTopNavigationPrimaryReveal;
Expand Down Expand Up @@ -536,7 +538,8 @@ bool ShouldShowContent()

bool IsOnLeftNav()
{
return Position == NavigationViewRepeaterPosition.LeftNav;
var position = Position;
return position == NavigationViewRepeaterPosition.LeftNav || position == NavigationViewRepeaterPosition.LeftFooter;
}

bool IsOnTopPrimary()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,12 +82,7 @@ protected override int GetPositionInSetCore()
{
int positionInSet = 0;

if (IsSettingsItem())
{
return 1;
}

if (IsOnTopNavigation())
if (IsOnTopNavigation() && !IsOnFooterNavigation())
{
positionInSet = GetPositionOrSetCountInTopNavHelper(AutomationOutput.Position);
}
Expand All @@ -103,14 +98,12 @@ protected override int GetSizeOfSetCore()
{
int sizeOfSet = 0;

if (IsSettingsItem())
{
return 1;
}

if (IsOnTopNavigation())
if (IsOnTopNavigation() && !IsOnFooterNavigation())
{
sizeOfSet = GetPositionOrSetCountInTopNavHelper(AutomationOutput.Size);
if (GetParentNavigationView() is { } navview)
{
sizeOfSet = GetPositionOrSetCountInTopNavHelper(AutomationOutput.Size);
}
}
else
{
Expand Down Expand Up @@ -244,14 +237,21 @@ bool IsSettingsItem()

bool IsOnTopNavigation()
{
return GetNavigationViewRepeaterPosition() != NavigationViewRepeaterPosition.LeftNav;
var position = GetNavigationViewRepeaterPosition();
return position != NavigationViewRepeaterPosition.LeftNav && position != NavigationViewRepeaterPosition.LeftFooter;
}

internal bool IsOnTopNavigationOverflow()
{
return GetNavigationViewRepeaterPosition() == NavigationViewRepeaterPosition.TopOverflow;
}

bool IsOnFooterNavigation()
{
var position = GetNavigationViewRepeaterPosition();
return position == NavigationViewRepeaterPosition.LeftFooter || position == NavigationViewRepeaterPosition.TopFooter;
}

NavigationViewRepeaterPosition GetNavigationViewRepeaterPosition()
{
if (Owner is NavigationViewItemBase navigationViewItem)
Expand All @@ -261,7 +261,7 @@ NavigationViewRepeaterPosition GetNavigationViewRepeaterPosition()
return NavigationViewRepeaterPosition.LeftNav;
}

ItemsRepeater GetParentRepeater()
ItemsRepeater GetParentItemsRepeater()
{
if (GetParentNavigationView() is { } navview)
{
Expand All @@ -281,9 +281,9 @@ int GetPositionOrSetCountInLeftNavHelper(AutomationOutput automationOutput)
{
int returnValue = 0;

if (GetParentRepeater() is { } repeater)
if (GetParentItemsRepeater() is { } repeater)
{
if (GetParent() is AutomationPeer parent)
if (FrameworkElementAutomationPeer.CreatePeerForElement(repeater) is AutomationPeer parent)
{
if (parent.GetChildren() is { } children)
{
Expand Down Expand Up @@ -343,7 +343,7 @@ int GetPositionOrSetCountInTopNavHelper(AutomationOutput automationOutput)
int returnValue = 0;
bool itemFound = false;

if (GetParentRepeater() is { } parentRepeater)
if (GetParentItemsRepeater() is { } parentRepeater)
{
if (parentRepeater.ItemsSourceView is { } itemsSourceView)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ void UpdateVisualState(bool useTransitions)
if (m_appliedTemplate)
{
const string groupName = "NavigationSeparatorLineStates";
var stateName = (Position != NavigationViewRepeaterPosition.TopPrimary)
var stateName = (Position != NavigationViewRepeaterPosition.TopPrimary && Position != NavigationViewRepeaterPosition.TopFooter)
? m_isClosedCompact
? "HorizontalLineCompact"
: "HorizontalLine"
Expand Down
18 changes: 17 additions & 1 deletion ModernWpf.Controls/NavigationView/NavigationViewItemsFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,12 @@ public void UserElementFactory(object newValue)
navigationViewItemPool = new List<NavigationViewItem>();
}

internal void SettingsItem(NavigationViewItemBase settingsItem)
{
m_settingsItem = settingsItem;
}


// Retrieve the element that will be displayed for a specific data item.
// If the resolved element is not derived from NavigationViewItemBase, wrap in a NavigationViewItem before returning.
protected override UIElement GetElementCore(ElementFactoryGetArgs args)
Expand All @@ -37,6 +43,12 @@ protected override UIElement GetElementCore(ElementFactoryGetArgs args)
{
object init()
{
// Do not template SettingsItem
if (m_settingsItem != null && m_settingsItem == args.Data)
{
return args.Data;
}

if (m_itemTemplateWrapper != null)
{
return m_itemTemplateWrapper.GetElement(args);
Expand Down Expand Up @@ -119,7 +131,10 @@ protected override void RecycleElementCore(ElementFactoryRecycleArgs args)
}
}

if (m_itemTemplateWrapper != null)
// Do not recycle SettingsItem
bool isSettingsItem = m_settingsItem != null && m_settingsItem == args.Element;

if (m_itemTemplateWrapper != null && !isSettingsItem)
{
m_itemTemplateWrapper.RecycleElement(args);
}
Expand All @@ -146,6 +161,7 @@ void UnlinkElementFromParent(ElementFactoryRecycleArgs args)
}

IElementFactoryShim m_itemTemplateWrapper;
NavigationViewItemBase m_settingsItem;
List<NavigationViewItem> navigationViewItemPool = new List<NavigationViewItem>();
}
}
Loading

0 comments on commit f74c8c7

Please sign in to comment.