Open HadriMX opened 4 years ago
I doesn't happen to me, I have more than 12 nav menu items and 4 distinct templates for them. Can you elaborate your issue with some sample code?
These are my resources, two DataTemplates and one Selector.
<Window.Resources>
<DataTemplate x:Key="MainNavigationViewTemplate">
<ui:NavigationViewItem Content="{Binding DisplayName, Mode=OneTime}" UseSystemFocusVisuals="True">
<ui:NavigationViewItem.Icon>
<ui:FontIcon Glyph="{Binding Glyph, Mode=OneTime}" />
</ui:NavigationViewItem.Icon>
</ui:NavigationViewItem>
</DataTemplate>
<DataTemplate x:Key="MainNavigationViewPendientesTemplate">
<ui:NavigationViewItem UseSystemFocusVisuals="True">
<ui:NavigationViewItem.Icon>
<ui:FontIcon Glyph="{Binding Glyph, Mode=OneTime}" />
</ui:NavigationViewItem.Icon>
<ui:NavigationViewItem.Content>
<mah:Badged Badge="{Binding TotalPendientesCount, FallbackValue={x:Null}}"
BadgeBackground="{DynamicResource SystemControlBackgroundAccentBrush}"
BadgeForeground="{DynamicResource SystemControlForegroundBaseHighBrush}"
BadgePlacementMode="Right">
<TextBlock Text="{Binding DisplayName, Mode=OneTime}" />
</mah:Badged>
</ui:NavigationViewItem.Content>
</ui:NavigationViewItem>
</DataTemplate>
<s:MainNavigationViewItemTemplateSelector x:Key="MyDataTemplateSelector"
DefaultTemplate="{StaticResource MainNavigationViewTemplate}"
PendientesTemplate="{StaticResource MainNavigationViewPendientesTemplate}" />
</Window.Resources>
My DataTemplateSelector:
public class MainNavigationViewItemTemplateSelector : DataTemplateSelector
{
public DataTemplate DefaultTemplate { get; set; }
public DataTemplate PendientesTemplate { get; set; }
public override DataTemplate SelectTemplate(object item, DependencyObject container)
{
Log(item); // here I write log to VS output window and practically it gets flooded, also UI thread seems to get so busy that app becomes totally unresponsive
var mainMenuItem = (IMainMenuItem)item;
return mainMenuItem.DisplayName != "Pendientes" ? DefaultTemplate : PendientesTemplate;
}
}
My NavigationView:
<ui:NavigationView x:Name="MainNavigationView"
IsBackButtonVisible="Collapsed"
IsSettingsVisible="True"
IsTabStop="False"
ItemInvoked="MainNavigationView_ItemInvoked"
MenuItemTemplateSelector="{StaticResource MyDataTemplateSelector}"
MenuItemsSource="{Binding MainMenuItems, Mode=OneWay}"
OpenPaneLength="240"
PaneDisplayMode="Left"
SelectionFollowsFocus="Enabled">
...
</ui:NavigationView>
My source collection (MenuItemsSource):
public ObservableCollection<IMainMenuItem> MainMenuItems { get; set; } = new ObservableCollection<IMainMenuItem>();
My interface IMainMenuItem:
public interface IMainMenuItem
{
bool CanGoBack { get; set; }
string DisplayName { get; }
string Glyph { get; }
}
Note: I try to use MVVM whenever I can, but mostly I use code-behind (hehe).
It does get broken 😅. It takes a while for rendering the icons and becomes unresponsive. But this didn't happen with mine even though I have multiple items
Hey @Kinnara, I can reproduce this issue (see ShankarBUS/ModernWpfTest repo). I can't find what's causing this 😑. This is causing too much startup delay.
ModernWpf version : 0.9.0
class
instead of an interface
, doesn't help 😑return item is PendientesNavItem ? PendientesTemplate : DefaultTemplate;
in the MainNavigationViewItemTemplateSelector's SelectTemplate method. Still doesn't help 😑And it's up-to you 😑
Thank you @HadriMX and @ShankarBUS. Below is a quick workaround for left nav. Top nav has a similar issue (actually worse) that seems to have a different cause and is not fixable by this workaround. Needs more investigating.
public class NavView : NavigationView
{
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
if (GetTemplateChild("MenuItemsHost") is ItemsRepeater leftNavRepeater)
{
leftNavRepeater.Layout = new NonVirtualizingStackLayout();
}
}
}
public class NonVirtualizingStackLayout : NonVirtualizingLayout
{
#region Orientation
public static readonly DependencyProperty OrientationProperty =
DependencyProperty.Register(
nameof(Orientation),
typeof(Orientation),
typeof(NonVirtualizingStackLayout),
new PropertyMetadata(Orientation.Vertical, OnOrientationChanged));
public Orientation Orientation
{
get => (Orientation)GetValue(OrientationProperty);
set => SetValue(OrientationProperty, value);
}
private static void OnOrientationChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
((NonVirtualizingStackLayout)d).InvalidateMeasure();
}
#endregion
protected override Size MeasureOverride(NonVirtualizingLayoutContext context, Size availableSize)
{
Size stackDesiredSize = new Size();
var children = context.Children;
Size layoutSlotSize = availableSize;
bool fHorizontal = Orientation == Orientation.Horizontal;
if (fHorizontal)
{
layoutSlotSize.Width = double.PositiveInfinity;
}
else
{
layoutSlotSize.Height = double.PositiveInfinity;
}
for (int i = 0, count = children.Count; i < count; ++i)
{
UIElement child = children[i];
if (child == null) { continue; }
child.Measure(layoutSlotSize);
Size childDesiredSize = child.DesiredSize;
if (fHorizontal)
{
stackDesiredSize.Width += childDesiredSize.Width;
stackDesiredSize.Height = Math.Max(stackDesiredSize.Height, childDesiredSize.Height);
}
else
{
stackDesiredSize.Width = Math.Max(stackDesiredSize.Width, childDesiredSize.Width);
stackDesiredSize.Height += childDesiredSize.Height;
}
}
if (fHorizontal)
{
if (double.IsFinite(availableSize.Height))
{
stackDesiredSize.Height = Math.Max(stackDesiredSize.Height, availableSize.Height);
}
}
else
{
if (double.IsFinite(availableSize.Width))
{
stackDesiredSize.Width = Math.Max(stackDesiredSize.Width, availableSize.Width);
}
}
return stackDesiredSize;
}
protected override Size ArrangeOverride(NonVirtualizingLayoutContext context, Size finalSize)
{
var children = context.Children;
bool fHorizontal = Orientation == Orientation.Horizontal;
Rect rcChild = new Rect(finalSize);
double previousChildSize = 0.0;
for (int i = 0, count = children.Count; i < count; ++i)
{
UIElement child = children[i];
if (child == null) { continue; }
if (fHorizontal)
{
rcChild.X += previousChildSize;
previousChildSize = child.DesiredSize.Width;
rcChild.Width = previousChildSize;
rcChild.Height = Math.Max(finalSize.Height, child.DesiredSize.Height);
}
else
{
rcChild.Y += previousChildSize;
previousChildSize = child.DesiredSize.Height;
rcChild.Height = previousChildSize;
rcChild.Width = Math.Max(finalSize.Width, child.DesiredSize.Width);
}
child.Arrange(rcChild);
}
return finalSize;
}
}
One thing that's confusing me is that this doesn't happen with my project (private), I have more than 12 dynamically generated nav menu items and 4 distinct (I guess -> header, separater, default navitem and hierarchical navitem) templates for them. What is the particular cause?
The issue seems no longer reproducible in left mode with the latest master version. In top mode it's still broken. WinUI 2.5 has the same issue.
Weird behavior, but there seems to be a loop in SelectTemplate method from MenuItemTemplateSelector only when there are more than 4 items in MenuItemsSource.