首页 > 解决方案 > UWP - 在 NavigationViewItems 上设置 IsEnabled

问题描述

我有一个带有NavigationView控件的 UWP 应用程序。导航项是通过MenuItemsSource在 XAML 中设置为类型对象的集合来创建的NavigationViewElement

<NavigationView 
        Style="{StaticResource MainPageNavControlStyle}" 
        HeaderTemplate="{StaticResource MainPageNavHeaderTemplate}"
        MenuItemsSource="{Binding NavigationViewElements}"
        MenuItemContainerStyleSelector="{StaticResource NavStyleSelector}"
        MenuItemTemplateSelector="{StaticResource NavItemTemplateSelector}"
        x:Name="NavigationViewControl" 
        CompactModeThresholdWidth="480" 
        ExpandedModeThresholdWidth="635" 
        OpenPaneLength="324"
        Loaded="OnControlLoaded"
        ItemInvoked="OnItemInvoked"
        IsTabStop="False"
        IsSettingsVisible="False"
>

我想将创建的IsEnabled属性绑定到. 我该怎么做?NavigationViewItemsNavigationViewElement

我对 a 有类似的问题ListBox。在这种情况下,我能够从 ListBox 派生一个新类,它根据绑定到的类中的数据(在本例中为 OptionItem)覆盖PrepareContainerForItemOverride()并设置IsEnabled标志ListBoxItem

protected override void PrepareContainerForItemOverride(Windows.UI.Xaml.DependencyObject element, object item)
{
    ListBoxItem lItem = element as ListBoxItem;
    OptionItem oItem = item as OptionItem;

    if (lItem != null && oItem != null)
    {
        lItem.IsEnabled = oItem.IsEnabled;
    }
    base.PrepareContainerForItemOverride(element, item);
}

是否有等价物NavigationView?或者是否有其他方式表明应该绑定的IsEnabled标志?NavigationViewItemNavigationViewElement.IsItemEnabled

更新 我查看了 Nico Zhu 提出的解决方案,但我不确定如何将其应用于我的要求。这可能是由于我对 XAML 缺乏经验。

在我的实现中,由于我的布局要求,我从 Selector 对象引用的 DataTemplates 不包含 NavigationViewItem 元素。我不是简单地设置 NavigationViewItem.Content 和 .Glyph,而是用一堆控件填充了一个 Grid。这是一个示例:

<DataTemplate x:Key="MainPageNavigationViewItem1LineTemplate">
    <Grid Margin="{StaticResource MainPageNavigationViewItemTopGridMargin}">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto"/>
            <ColumnDefinition Width="*"/>
        </Grid.ColumnDefinitions>
        <FontIcon Glyph="{Binding Glyph, FallbackValue=&#xE14E;}" FontFamily="{Binding FontFamily, FallbackValue=xGlyph}" FontSize="{StaticResource MainPageNavigationViewItemGlyphFontSize}" VerticalAlignment="Center" Margin="{StaticResource MainPageNavigationViewItemGlyphMargin}"/>
        <StackPanel Grid.Column="1" Margin="{StaticResource MainPageNavigationViewItemTextMargin}" HorizontalAlignment="Stretch" VerticalAlignment="Center">
            <TextBlock x:Name="Header"
                               Text="{Binding TheSummaryHelper.SummaryHeaderLabel, FallbackValue=TheHeader}" 
                               Style="{StaticResource DefaultFontStyle}"
                               />
            <TextBlock x:Name="Line1" 
                               Text="{Binding TheSummaryHelper.Line1.DisplayString, FallbackValue=TheFirstLine}" 
                               Visibility="{Binding TheSummaryHelper.Line1.ItemVisibility, FallbackValue=Visible}" 
                               Style="{StaticResource SmallSummaryTextStyle}"
                               />
        </StackPanel>
    </Grid>
</DataTemplate>

结果看起来像这样,项目的内容设置等于 Grid 的内容:

在此处输入图像描述

这正是我所需要的,但我不知道如何将项目的 IsEnabled 属性绑定到 NavigationViewElement.IsItemEnabled。

当我尝试遵循建议的模型时,将 NavigationViewItem 添加到 DataTemplate 中,如下所示:

        <misc:MainPageNavigationViewItemTemplateSelector
            x:Key="NavItemTemplateSelector"
            >
            <misc:MainPageNavigationViewItemTemplateSelector.ItemTemplate>
                <DataTemplate x:DataType="vm_misc:NavigationViewElement">
                    <NavigationViewItem IsEnabled="{x:Bind IsItemEnabled}" Content="{x:Bind TheSummaryHelper.SummaryHeaderLabel}">
                    </NavigationViewItem>
                </DataTemplate>
            </misc:MainPageNavigationViewItemTemplateSelector.ItemTemplate>
        </misc:MainPageNavigationViewItemTemplateSelector>

然后我可以根据需要绑定 IsEnabled 属性,但 UI 无法正确绘制。该项目的内容似乎在我已经拥有的内容之上添加了第二个 NavigationViewItem。单击带有文本的区域没有任何作用 - 我必须单击浅灰色区域之外的项目才能进行导航。

在此处输入图像描述

对我做错了什么有任何见解吗?总之,我希望找到一种方法来自定义 NavigationViewItem 的显示内容,同时还将 IsEnabled 属性绑定到模型中 NavigationViewElement 上的属性。

标签: c#uwpuwp-xaml

解决方案


与模型绑定MenuItemsSource,可以参考官方代码示例。在最新版本中,我们添加了关于设置数据源的新功能MenuItemsSource。如果要启用或禁用NavigationViewItem,可以IsEnabled在模型中创建属性然后绑定它。请检查以下代码。

Xaml 代码

<Page.Resources>
    <local:MenuItemTemplateSelector x:Key="selector">
        <local:MenuItemTemplateSelector.ItemTemplate>
            <DataTemplate x:DataType="local:Category" >
                <NavigationViewItem Content="{x:Bind Name}" 
                                    ToolTipService.ToolTip="{x:Bind Tooltip}" 
                                    IsEnabled="{x:Bind IsEnabled}" >
                    <NavigationViewItem.Icon>
                        <SymbolIcon Symbol="{x:Bind Glyph}" />
                    </NavigationViewItem.Icon>
                </NavigationViewItem>
            </DataTemplate>
        </local:MenuItemTemplateSelector.ItemTemplate >
    </local:MenuItemTemplateSelector>
</Page.Resources>
<Grid>
    <NavigationView x:Name="nvSample" 
            MenuItemTemplateSelector="{StaticResource selector}"                      
            MenuItemsSource="{x:Bind Categories, Mode=OneWay}" />

</Grid>

代码背后

public sealed partial class MainPage : Page
{
    public MainPage()
    {
        this.InitializeComponent();
        Categories = new ObservableCollection<CategoryBase>();
        Categories.Add(new Category { Name = "Category 1", Glyph = Symbol.Home, Tooltip = "This is category 1", IsEnabled = false });
        Categories.Add(new Category { Name = "Category 2", Glyph = Symbol.Keyboard, Tooltip = "This is category 2", IsEnabled = true });
        Categories.Add(new Category { Name = "Category 3", Glyph = Symbol.Library, Tooltip = "This is category 3" , IsEnabled = false });
        Categories.Add(new Category { Name = "Category 4", Glyph = Symbol.Mail, Tooltip = "This is category 4", IsEnabled = true });
    }

    public ObservableCollection<CategoryBase> Categories { get;  set; }
}


public class CategoryBase { }

public class Category : CategoryBase
{
    public string Name { get; set; }
    public string Tooltip { get; set; }
    public Symbol Glyph { get; set; }
    public bool IsEnabled { get; set; }
}

public class Separator : CategoryBase { }

public class Header : CategoryBase
{
    public string Name { get; set; }
}

[ContentProperty(Name = "ItemTemplate")]
class MenuItemTemplateSelector : DataTemplateSelector
{
    public DataTemplate ItemTemplate { get; set; }
    protected override DataTemplate SelectTemplateCore(object item)
    {
        return item is Separator ? SeparatorTemplate : item is Header ? HeaderTemplate : ItemTemplate;
    }
    internal DataTemplate HeaderTemplate = (DataTemplate)XamlReader.Load(
       @"<DataTemplate xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation'>
               <NavigationViewItemHeader Content='{Binding Name}' />
              </DataTemplate>");

    internal DataTemplate SeparatorTemplate = (DataTemplate)XamlReader.Load(
        @"<DataTemplate xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation'>
                <NavigationViewItemSeparator />
              </DataTemplate>");
}

在此处输入图像描述



更新一

问题的关键是我们不能DataTemplate在1803中使用。一般来说,NavigationViewItem在1803中创建我们经常使用以下解决方案。

Xaml

<NavigationView x:Name="nvSample" MenuItemsSource="{x:Bind NavItems}" >

</NavigationView>

背后的代码

public ObservableCollection<Category> Categories { get; set; }
public MainPage()
{
    this.InitializeComponent();
    Categories = new ObservableCollection<Category>();
    Categories.Add(new Category { Name = "Category 1", Glyph = Symbol.Home, Tooltip = "This is category 1", IsEnabled = false });
    Categories.Add(new Category { Name = "Category 2", Glyph = Symbol.Keyboard, Tooltip = "This is category 2", IsEnabled = true });
    Categories.Add(new Category { Name = "Category 3", Glyph = Symbol.Library, Tooltip = "This is category 3", IsEnabled = true });
    Categories.Add(new Category { Name = "Category 4", Glyph = Symbol.Mail, Tooltip = "This is category 4", IsEnabled = true });

}
public IEnumerable<NavigationViewItemBase> NavItems
{
    get
    {
        return Categories.Select(
               b => (new NavigationViewItem
               {
                   Content = b.Name,
                   Icon = new SymbolIcon(b.Glyph),
                   IsEnabled = b.IsEnabled,
               })
        );
    }
}

简而言之,我们需要将数据模型转换为 NavigationViewItem. 但不能在 1803 内使用 DataTemplate。请试试这个。有关更多详细信息,您还可以参考此案例


推荐阅读