Visually Located

XAML and GIS

Customizing the “selected” HubSection Header

I saw a question today about changing the foreground color of the “visible” or “selected” HubSection. Someone had pointed out that I have a behavior for getting the selected index of a Hub and it could be combined with a converter to give the desired output. I thought the solution to this problem was actually quiet simpler. If we can change the visual state of the hub sections when they change, we can give them a “selected” or “unselected” state. For this we can listen to the SectionsIsViewChanged event

public class CustomHub : Hub
{
    HubSection _lastSelectedSection = null;
 
    public CustomHub()
    {
        SectionsInViewChanged += OnSectionsInViewChanged;
    }
 
    private void OnSectionsInViewChanged(object sender, SectionsInViewChangedEventArgs sectionsInViewChangedEventArgs)
    {
        if (_lastSelectedSection == SectionsInView[0]) return;
        
        VisualStateManager.GoToState(SectionsInView[0], "Selected", true);
        if (_lastSelectedSection != null)
        {
            VisualStateManager.GoToState(_lastSelectedSection, "Unselected", true);                
        }
        _lastSelectedSection = SectionsInView[0];
    }
}

NOTE: This sample does not set all sections to the “Unselected” state to begin with. For this sample, the state is blank so it doesn’t offer anything.

Now it’s just a matter of modifying the style of the HubSection to have these states.

Use the following style for the section

<Style TargetType="HubSection">
    <Setter Property="HorizontalContentAlignment" Value="Stretch"/>
    <Setter Property="VerticalContentAlignment" Value="Stretch"/>
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="HubSection">
                <Grid Background="{TemplateBinding Background}" Margin="{StaticResource HubSectionMarginThickness}">
                    <Grid.RowDefinitions>
                        <RowDefinition Height="auto"/>
                        <RowDefinition Height="auto"/>
                        <RowDefinition Height="*"/>
                    </Grid.RowDefinitions>
                    <VisualStateManager.VisualStateGroups>
                        <VisualStateGroup x:Name="SelectionStates">
                            <VisualState x:Name="Selected">
                                <Storyboard>
                                    <ColorAnimation Duration="0" To="#FFF30707" Storyboard.TargetProperty="(Control.Foreground).(SolidColorBrush.Color)" Storyboard.TargetName="Header" d:IsOptimized="True"/>
                                </Storyboard>
                            </VisualState>
                            <VisualState x:Name="Unselected"/>
                        </VisualStateGroup>
                    </VisualStateManager.VisualStateGroups>                            
                    <Grid.RenderTransform>
                        <CompositeTransform x:Name="WrappingTransform"/>
                    </Grid.RenderTransform>
                    <Rectangle x:Name="HubHeaderPlaceholder" Grid.Row="0"/>
                    <ContentControl x:Name="Header" CharacterSpacing="{StaticResource HubSectionHeaderCharacterSpacing}" ContentTemplate="{TemplateBinding HeaderTemplate}" Content="{TemplateBinding Header}" FontWeight="SemiBold" FontSize="{StaticResource HubSectionHeaderFontSize}" FontFamily="{StaticResource PhoneFontFamilyNormal}" HorizontalAlignment="Left" Margin="{StaticResource HubSectionHeaderMarginThickness}" Grid.Row="1">
                        <ContentControl.RenderTransform>
                            <CompositeTransform x:Name="StickyHeaderTransform"/>
                        </ContentControl.RenderTransform>
                    </ContentControl>
                    <ContentPresenter x:Name="ContentPresenter" ContentTemplate="{TemplateBinding ContentTemplate}" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}" Grid.Row="2" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
                </Grid>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

Notice the VisualStateGroup with the “Selected” and “Unselected” states. You’ll want to add this style to your page, or app resources. Using this new way of styling does require the use of the new CustomHub control over the standard Hub control.

<controls:CustomHub Header="Hello world">
    <HubSection Header="one">
 
    </HubSection>
    <HubSection Header="two">
 
    </HubSection>
    <HubSection Header="three">
 
    </HubSection>
</controls:CustomHub>

What other ways can you think to customize the ”selected” HubSection?