1
votes

I have been having a lot of difficulties writing in xaml, understanding the visual state manager and using styles.

I have been creating a UWP app and largely using C# to develop my UI. However, I wanted to switch to using xaml but am inexperienced with markup languages.

What I am trying to achieve, and for the life of me can not figure out, is to create styles based on a "parent" style which has additional states, mostly to change the visibility.

Here is an example, I have created an instance of a default style called "NavigationViewItemStyle". I then have a few styles based on NavigationViewItemStyle. What I want to do is add additional states which I can trigger in C# to change the visibility of controls.

Below is my default style... just a simple copy

      <Style x:Key="NavigationViewItemStyle" TargetType="NavigationViewItem">
            <Setter Property="Foreground" Value="{ThemeResource NavigationViewItemForeground}"/>
            <Setter Property="Background" Value="{ThemeResource NavigationViewItemBackground}"/>
            <Setter Property="BorderBrush" Value="{ThemeResource NavigationViewItemBorderBrush}"/>
            <Setter Property="BorderThickness" Value="{StaticResource NavigationViewItemBorderThickness}"/>
            <Setter Property="UseSystemFocusVisuals" Value="True"/>
            <Setter Property="HorizontalContentAlignment" Value="Stretch"/>
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="NavigationViewItem">
                        <Grid x:Name="LayoutRoot" Background="{TemplateBinding Background}" Height="40" Control.IsTemplateFocusTarget="True">
                            <VisualStateManager.VisualStateGroups>
                                <VisualStateGroup x:Name="PointerStates">
                                    <VisualState x:Name="Normal"/>
                                    <VisualState x:Name="PointerOver">
                                        <VisualState.Setters>
                                            <Setter Target="LayoutRoot.(RevealBrush.State)" Value="PointerOver"/>
                                            <Setter Target="LayoutRoot.Background" Value="{ThemeResource NavigationViewItemBackgroundPointerOver}"/>
                                            <Setter Target="RevealBorder.BorderBrush" Value="{ThemeResource NavigationViewItemBorderBrushPointerOver}"/>
                                            <Setter Target="ContentPresenter.Foreground" Value="{ThemeResource NavigationViewItemForegroundPointerOver}"/>
                                        </VisualState.Setters>
                                    </VisualState>
                                    <VisualState x:Name="Pressed">
                                        <VisualState.Setters>
                                            <Setter Target="LayoutRoot.(RevealBrush.State)" Value="Pressed"/>
                                            <Setter Target="LayoutRoot.Background" Value="{ThemeResource NavigationViewItemBackgroundPressed}"/>
                                            <Setter Target="RevealBorder.BorderBrush" Value="{ThemeResource NavigationViewItemBorderBrushPressed}"/>
                                            <Setter Target="ContentPresenter.Foreground" Value="{ThemeResource NavigationViewItemForegroundPressed}"/>
                                        </VisualState.Setters>
                                    </VisualState>
                                    <VisualState x:Name="Selected">
                                        <VisualState.Setters>
                                            <Setter Target="LayoutRoot.Background" Value="{ThemeResource NavigationViewItemBackgroundSelected}"/>
                                            <Setter Target="RevealBorder.BorderBrush" Value="{ThemeResource NavigationViewItemBorderBrushSelected}"/>
                                            <Setter Target="ContentPresenter.Foreground" Value="{ThemeResource NavigationViewItemForegroundSelected}"/>
                                        </VisualState.Setters>
                                    </VisualState>
                                    <VisualState x:Name="PointerOverSelected">
                                        <VisualState.Setters>
                                            <Setter Target="LayoutRoot.(RevealBrush.State)" Value="PointerOver"/>
                                            <Setter Target="LayoutRoot.Background" Value="{ThemeResource NavigationViewItemBackgroundSelectedPointerOver}"/>
                                            <Setter Target="RevealBorder.BorderBrush" Value="{ThemeResource NavigationViewItemBorderBrushSelectedPointerOver}"/>
                                            <Setter Target="ContentPresenter.Foreground" Value="{ThemeResource NavigationViewItemForegroundSelectedPointerOver}"/>
                                        </VisualState.Setters>
                                    </VisualState>
                                    <VisualState x:Name="PressedSelected">
                                        <VisualState.Setters>
                                            <Setter Target="LayoutRoot.(RevealBrush.State)" Value="Pressed"/>
                                            <Setter Target="LayoutRoot.Background" Value="{ThemeResource NavigationViewItemBackgroundSelectedPressed}"/>
                                            <Setter Target="RevealBorder.BorderBrush" Value="{ThemeResource NavigationViewItemBorderBrushSelectedPressed}"/>
                                            <Setter Target="ContentPresenter.Foreground" Value="{ThemeResource NavigationViewItemForegroundSelectedPressed}"/>
                                        </VisualState.Setters>
                                    </VisualState>
                                </VisualStateGroup>
                                <VisualStateGroup x:Name="DisabledStates">
                                    <VisualState x:Name="Enabled"/>
                                    <VisualState x:Name="Disabled">
                                        <VisualState.Setters>
                                            <Setter Target="RevealBorder.BorderBrush" Value="{ThemeResource NavigationViewItemBorderBrushCheckedDisabled}"/>
                                            <Setter Target="LayoutRoot.Opacity" Value="{ThemeResource ListViewItemDisabledThemeOpacity}"/>
                                        </VisualState.Setters>
                                    </VisualState>
                                </VisualStateGroup>
                                <VisualStateGroup x:Name="IconStates">
                                    <VisualState x:Name="IconVisible"/>
                                    <VisualState x:Name="IconCollapsed">
                                        <VisualState.Setters>
                                            <Setter Target="IconBox.Visibility" Value="Collapsed"/>
                                            <Setter Target="IconColumn.Width" Value="16"/>
                                        </VisualState.Setters>
                                    </VisualState>
                                </VisualStateGroup>
                            </VisualStateManager.VisualStateGroups>
                            <Grid HorizontalAlignment="Left" VerticalAlignment="Center">
                                <Rectangle x:Name="SelectionIndicator" Fill="{ThemeResource NavigationViewSelectionIndicatorForeground}" Height="24" Opacity="0.0" Width="6"/>
                            </Grid>
                            <Border x:Name="RevealBorder" BorderThickness="{TemplateBinding BorderThickness}" BorderBrush="{TemplateBinding BorderBrush}"/>
                            <Grid x:Name="ContentGrid" HorizontalAlignment="Left" Height="40">
                                <Grid.ColumnDefinitions>
                                    <ColumnDefinition x:Name="IconColumn" Width="48"/>
                                    <ColumnDefinition Width="*"/>
                                </Grid.ColumnDefinitions>
                                <ToolTipService.ToolTip>
                                    <ToolTip x:Name="ToolTip"/>
                                </ToolTipService.ToolTip>
                                <Viewbox x:Name="IconBox" Child="{TemplateBinding Icon}" Margin="16,12"/>
                                <ContentPresenter x:Name="ContentPresenter" ContentTemplate="{TemplateBinding ContentTemplate}" Content="{TemplateBinding Content}" ContentTransitions="{TemplateBinding ContentTransitions}" Grid.Column="1" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
                            </Grid>
                        </Grid>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>

I've then created a custom style based on my default style

<Style x:Key="HomeNavigationViewItemStyle" TargetType="NavigationViewItem" BasedOn="{StaticResource NavigationViewItemStyle}">
</Style>

What I can't work out is how I include additional states within my custom style to change the visibility of the control.

I.e. I have 4 different states the application can be in, and depending on the state certain navigationviewitems are either visible or collapsed.

To make things easy I want

<VisualStateGroup x:Name="NavigationViewStates">
    <VisualState x:Name="NavigationViewState1">
        <VisualState.Setters>
            <Setter Target="Visibility" Value="Visible"/>
        </VisualState.Setters>
    </VisualState>
    <VisualState x:Name="NavigationViewState2">
        <VisualState.Setters>
            <Setter Target="Visibility" Value="Collapsed"/>
        </VisualState.Setters>
    </VisualState>
    <VisualState x:Name="NavigationViewState3">
        <VisualState.Setters>
            <Setter Target="Visibility" Value="Collapsed"/>
        </VisualState.Setters>
    </VisualState>
</VisualStateGroup>

But have no idea how to get this to work....

Can anybody help me or steer me in the right direction?

1
VisualStateGroup should be declared in XAML as part of control template. How did you want to trigger these visual states? In which conditions? - Xie Steven
Thanks for your reply and yes this is where I'm having difficulty in my "base" style I have a VisualStateGroup attached to the control template. In my "child" style I have tried to attached a second VisualStateGroup to the control template that is somewhat independent (i.e. a visual state in the "base" visual state group my be triggered in combination with a "child" visual state). I want to triggered my "child" visual states through code (i.e. visualstatemanager.gotostate(item1, "NavigationViewState1") - Soggy
I want to know under which conditions you want to trigger these visual states. For example, In which condition, you want to trigger the 'NavigationViewState1'? - Xie Steven
I have a command bar in my navigation pane with 3 appbartogglebuttons. A change in which appbartogglebutton is active (i.e. toggling an appbartogglebutton on will turn off the other 2) will change the visual state of the navigation pane content. - Soggy
So, did you want to show/hide all the NavigationViewItems in NavigationView through the appbartogglebutton's status? - Xie Steven

1 Answers

0
votes

depending on which style is attached the item will be either visible or collapsed

There's an easy way to get your target. You could use NavigationView.MenuItemContainerStyleSelector Property. You need to make a custom style selector to apply different style for NavigationViewItem, and in code-behind(the custom style selector class), you could show/hide the NavigationViewItem according to the item. By this way, you do not need to use visual state.

See the following code for reference:

<Page.Resources>
    <Style x:Key="s1" TargetType="NavigationViewItem">
        <Setter Property="Visibility" Value="Visible"></Setter>
    </Style>
    <Style x:Key="s2" TargetType="NavigationViewItem">
        <Setter Property="Visibility" Value="Collapsed"></Setter>
    </Style>
    <Style x:Key="s3" TargetType="NavigationViewItem">
        <Setter Property="Visibility" Value="Visible"></Setter>
    </Style>
    <local:CustomStyleSelector x:Key="customStyleSelector" style1="{StaticResource s1}" style2="{StaticResource s2}" style3="{StaticResource s3}"></local:CustomStyleSelector>
</Page.Resources>

<Grid>
    <NavigationView x:Name="NavView"
                IsSettingsVisible="True"
                Header="Welcome" MenuItemContainerStyleSelector="{StaticResource customStyleSelector}">
        <NavigationView.MenuItems>
            <NavigationViewItem Content="Home" x:Name="home" Tag="home">
                <NavigationViewItem.Icon>
                    <FontIcon Glyph="&#xE10F;"/>
                </NavigationViewItem.Icon>
            </NavigationViewItem>
            <NavigationViewItem Icon="AllApps" Content="item1" x:Name="apps" Tag="apps"/>
            <NavigationViewItem Icon="Video" Content="item2" x:Name="games" Tag="games"/>
            <NavigationViewItem Icon="Audio" Content="item3" x:Name="music" Tag="music"/>
        </NavigationView.MenuItems>
    </NavigationView>
</Grid>
public class CustomStyleSelector: StyleSelector
{
    public Style style1 { get; set; }
    public Style style2 { get; set; }
    public Style style3 { get; set; }
    protected override Style SelectStyleCore(object item, DependencyObject container)
    {
        if (item is NavigationViewItem)
        {
            if ((item as NavigationViewItem).Content.ToString() == "item1")
            {
                return style1;
            }
            if ((item as NavigationViewItem).Content.ToString() == "item2")
            {
                return style2;
            }
            if ((item as NavigationViewItem).Content.ToString() == "item3")
            {
                return style3;
            }
        }
        return base.SelectStyleCore(item, container);
    }
}