UWP - 在 NavigationViewItems 上设置 IsEnabled [英] UWP - setting IsEnabled on NavigationViewItems

查看:26
本文介绍了UWP - 在 NavigationViewItems 上设置 IsEnabled的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

我想将创建的 NavigationViewItemsIsEnabled 属性绑定到 NavigationViewElement 上的属性.我该怎么做?

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

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 的等效项? 或者是否有其他方法来指示 NavigationViewItemIsEnabled 标志应该绑定到NavigationViewElement.IsItemEnabled?

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

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

<Grid Margin="{StaticResource MainPageNavigationViewItemTopGridMargin}"><Grid.ColumnDefinitions><ColumnDefinition Width="自动"/><ColumnDefinition Width="*"/></Grid.ColumnDefinitions><FontIcon Glyph="{Binding Glyph, FallbackValue=&#xE14E;}" FontFamily="{Binding FontFamily, FallbackValue=xGlyph}" FontSize="{StaticResource MainPageNavigationViewItemGlyphFontSize}" VerticalAlignment="Center" Margin="{StaticResource MainPageMarginViewGlyph}}"/><StackPanel Grid.Column="1" Margin="{StaticResource MainPageNavigationViewItemTextMargin}" Horizo​​ntalAlignment="Stretch" VerticalAlignment="Center"><TextBlock x:Name="标题"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></网格></数据模板>

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

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

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

 

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

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

解决方案

MenuItemsSource 与模型的绑定,可以参考



更新一

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

Xaml

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

背后的代码

public ObservableCollection类别 { 得到;放;}公共主页(){this.InitializeComponent();Categories = new ObservableCollection();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 });}公共 IEnumerable导航项{得到{返回类别.选择(b =>(新的 NavigationViewItem{内容 = b.名称,Icon = new SymbolIcon(b.Glyph),IsEnabled = b.IsEnabled,}));}}

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

I have a UWP app with a NavigationView control. The navigation items are created by setting MenuItemsSource in the XAML to a collection of objects of type 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"
>

I would like to bind the IsEnabled property of the NavigationViewItems that get created to a property on NavigationViewElement. How might I do that?

I had a similar question for a ListBox. In that case, I was able to derive a new class from ListBox that overrides PrepareContainerForItemOverride() and sets the IsEnabled flag of the ListBoxItem based on the data in the class to which it is bound (OptionItem, in this case)

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);
}

Is there an equivalent for NavigationView? Or is there some other way to indicate that the IsEnabled flag for the NavigationViewItem should be bound to NavigationViewElement.IsItemEnabled?

Update I looked at the solution proposed by Nico Zhu but I am not sure how to apply it to my requirements. That could be due to my inexperience with XAML.

In my implementation, the DataTemplates that I reference from my Selector object do not include a NavigationViewItem element, due to my layout requirements. Rather than simply setting NavigationViewItem.Content and .Glyph, I populate a Grid with a bunch of controls. Here is a sample:

<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>

The result looks like this, with the item's contents set equal to those of the Grid:

It's exactly what I need, but I couldn't figure out how to bind the IsEnabled property of the item to NavigationViewElement.IsItemEnabled.

When I tried to follow the model suggested, adding a NavigationViewItem to the DataTemplate like this:

        <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>

then I am able to bind the IsEnabled property as desired, but the UI does not draw properly. The Content for the item seems to add a second NavigationViewItem on top of the one I already had. Clicking the area with the text does nothing - I have to click on the item outside the light gray area to cause navigation to occur.

Any insights into what I'm doing wrong? In summary, I am hoping to find a way to both customize the display contents of the NavigationViewItem while also binding the IsEnabled property to a property on the NavigationViewElement in my model.

解决方案

For binding MenuItemsSource with model, you could refer official code sample. In latest version we have added new feature about setting datasource for MenuItemsSource. If you want to enable or disable NavigationViewItem, you could make IsEnabled property in the model then bind it. Please check the following code.

Xaml Code

<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>

Code Behind

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>");
}



Update One

The key to the problem is that we can’t use DataTemplate in 1803. In general, for creating NavigationViewItem in 1803 we often use the following solution.

Xaml

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

</NavigationView>

Code behind

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,
               })
        );
    }
}

In short, we need convert Data Model to NavigationViewItem. But not using DataTemplate within 1803. Please try this. For more detail you could also refer this case.

这篇关于UWP - 在 NavigationViewItems 上设置 IsEnabled的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆