web-dev-qa-db-fra.com

UWP - paramètre IsEnabled sur NavigationViewItems

J'ai une application UWP avec un contrôle NavigationView. Les éléments de navigation sont créés en définissant MenuItemsSource dans XAML sur une collection d'objets de 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"
>

Je voudrais lier la propriété IsEnabled de la NavigationViewItems créée à une propriété sur NavigationViewElement. Comment pourrais-je faire ça? 

J'ai eu une question similaire pour un ListBox. Dans ce cas, j'ai pu dériver une nouvelle classe de ListBox qui remplace PrepareContainerForItemOverride() et définit l'indicateur IsEnabled de ListBoxItem en fonction des données de la classe à laquelle elle est liée (OptionItem, dans ce cas)

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

Existe-t-il un équivalent pour NavigationView? ou existe-t-il un autre moyen d'indiquer que l'indicateur IsEnabled pour NavigationViewItem devrait être lié à NavigationViewElement.IsItemEnabled?

Mise à jour J'ai examiné la solution proposée par Nico Zhu mais je ne sais pas comment l'appliquer à mes besoins. Cela pourrait être dû à mon inexpérience avec XAML. 

Dans mon implémentation, les DataTemplates que je référence à partir de mon objet Selector n'incluent pas d'élément NavigationViewItem, en raison de mes exigences de mise en page. Plutôt que de définir simplement NavigationViewItem.Content et .Glyph, je remplis une grille avec un tas de contrôles. Voici un échantillon:

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

Le résultat ressemble à ceci, le contenu de l'élément étant égal à celui de la grille:

 enter image description here

C'est exactement ce dont j'ai besoin, mais je ne savais pas comment lier la propriété IsEnabled de l'élément à NavigationViewElement.IsItemEnabled.

Quand j'ai essayé de suivre le modèle suggéré, ajouter un objet NavigationViewItem au DataTemplate comme ceci:

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

je peux alors lier la propriété IsEnabled comme souhaité, mais l'interface utilisateur ne dessine pas correctement. Le contenu de l'élément semble ajouter un deuxième élément NavigationViewItem à celui que j'avais déjà. Cliquer sur la zone avec le texte ne fait rien - je dois cliquer sur l'élément en dehors de la zone gris clair pour que la navigation se produise.

 enter image description here

Des idées sur ce que je fais mal? En résumé, j'espère trouver un moyen de personnaliser le contenu d'affichage de NavigationViewItem tout en liant la propriété IsEnabled à une propriété de NavigationViewElement dans mon modèle.

6
Rich S

Pour lier MenuItemsSource avec le modèle, vous pouvez vous référer à exemple de code officiel . Dans la dernière version, nous avons ajouté une nouvelle fonctionnalité sur la définition de la source de données pour MenuItemsSource. Si vous souhaitez activer ou désactiver NavigationViewItem, vous pouvez créer la propriété IsEnabled dans le modèle, puis le lier. Veuillez vérifier le code suivant.

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

Code Derrière

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

 enter image description here



Mise à jour un

La clé du problème est que nous ne pouvons pas utiliser DataTemplate en 1803. En général, pour créer NavigationViewItem en 1803, nous utilisons souvent la solution suivante.

Xaml

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

</NavigationView>

Code derrière

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

En bref, nous devons convertir le modèle de données en NavigationViewItem. Mais n'utilisez pas DataTemplate dans 1803. Essayez ceci. Pour plus de détails, vous pouvez également vous référer à ce cas .

3
Nico Zhu - MSFT

Si vous pouvez utiliser 1809, le comportement ici autorise NavigationViewItems dans un DataTemplate comme vous le faites actuellement. 

Dans les versions antérieures, toutefois, NavigationViewItem n'était autorisé que dans la propriété MenuItems et ne pouvait pas être utilisé dans la propriété MenuItemTemplate. Vous pouvez donc déplacer vos éléments vers la propriété MenuItems sans DataTemplate.

Si vous utilisez une version antérieure et que vous souhaitez utiliser la propriété MenuItemTemplate avec un DataTemplate, vous devez utiliser autre chose que NavigationViewItem. Par exemple, vous pouvez utiliser un bouton avec Button.Content défini sur une grille. Dans la grille, vous pouvez inclure quelque chose comme un SymbolIcon et TextBlock. Il faudrait un peu de travail pour que le formatage soit correct.

Si vous devez utiliser 1803, je vous suggère de déplacer les NavigationViewItems vers la propriété MenuItems du NavigationView lui-même. 

Pour obtenir de la documentation, veuillez consulter: https://docs.Microsoft.com/en-us/uwp/api/windows.ui.xaml.controls.navigationviewitem

0