Setting Focus Directly to Expander Button
I am trying to set focus to the `ToggleButton` of an `Expander` element when the user control gains focus. Is there a way to reference the internal element of the Expander in the target field of SetFocusAction? Is there any other way of setting focus like this through XAML?
The goal of this is to have the focus set to the button as soon as the screen becomes visible so the user can click it without needing to navigate first.
At runtime, the hierarchy looks something like this:
> Expander (Focus goes here)
>> Dock Panel
>>>ToggleButton (Want focus to go here)
It would be nice if there was the option to do something like the line below but I haven't found any example doing something similar yet:
Any help or ideas are much appreciated!
The goal of this is to have the focus set to the button as soon as the screen becomes visible so the user can click it without needing to navigate first.
Code: Select all
<Grid x:Name="StateTriggers">
<b:Interaction.Triggers>
<b:PropertyChangedTrigger Binding="{Binding IsVisible, ElementName=MyContainer}">
<noesis:SetFocusAction TargetName="MyExpander"/>
</b:PropertyChangedTrigger>
</b:Interaction.Triggers>
</Grid>
<Grid x:Name="MyContainer" Width="400">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="80"/>
</Grid.RowDefinitions>
<ScrollViewer x:Name="Content" Grid.Row="0" Margin="20,20,10,20" VerticalAlignment="Top" VerticalScrollBarVisibility="Visible">
<StackPanel>
<Expander x:Name="MyExpander" Template="{StaticResource MyExpanderTemplate}" OverridesDefaultStyle="True" IsExpanded="True" DataContext="{Binding MyExpanderModel}" KeyboardNavigation.DirectionalNavigation="Continue">
<Expander.Header>
<TextBlock Text="This is an expander"/>
</Expander.Header>
<ItemsControl x:Name="MyExpanderItems" ItemTemplate="{StaticResource MyExpanderItemTemplate}" ItemsSource="{Binding Items}" Margin="0,10,0,0" Focusable="False">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Orientation="Vertical"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</Expander>
</StackPanel>
</ScrollViewer>
</Grid>
> Expander (Focus goes here)
>> Dock Panel
>>>ToggleButton (Want focus to go here)
It would be nice if there was the option to do something like the line below but I haven't found any example doing something similar yet:
Code: Select all
<noesis:SetFocusAction TargetName="MyExpander.DockPanel.ToggleButton"/>
-
sfernandez
Site Admin
- Posts: 3134
- Joined:
Re: Setting Focus Directly to Expander Button
You cannot access template elements from outside the control like that. I suggest you just set the focus on the Expander, and then move it down so its ToggleButton acquires the focus, something like this:
Could you try that?
Code: Select all
<Grid
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:b="http://schemas.microsoft.com/xaml/behaviors"
xmlns:noesis="clr-namespace:NoesisGUIExtensions;assembly=Noesis.GUI.Extensions">
<b:Interaction.Triggers>
<b:EventTrigger EventName="Loaded">
<noesis:SetFocusAction TargetName="expand"/>
<noesis:MoveFocusAction Direction="Down"/>
</b:EventTrigger>
</b:Interaction.Triggers>
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
<Button Content="First Button"/>
<Expander x:Name="expand" Header="Expander" IsExpanded="True">
<Ellipse Height="100" Fill="Red"/>
</Expander>
<Button Content="Second Button"/>
</StackPanel>
</Grid>
Re: Setting Focus Directly to Expander Button
This does work, Thank you!
There is however, an additional edge case that I am hitting. The expander is part of a grid and a VisualStateManager is setup to periodically hide and show the grid that wraps the expander. Is there a way to set focus when the visibility of the grid container is updated and not only when the entire control is first loaded?
I have tried these things and others without much success:
- have an EventTrigger on "IsVisibleChanged" inside of grid1
- have an EventTrigger on "IsLoaded" inside of grid1
- have a PropertyChangedTrigger for the visibility of grid1 inside of the root grid
Is there a good way of updating focus with the states of the VisualStateManager or at least to correct the focus in response to the visual state changing?
There is however, an additional edge case that I am hitting. The expander is part of a grid and a VisualStateManager is setup to periodically hide and show the grid that wraps the expander. Is there a way to set focus when the visibility of the grid container is updated and not only when the entire control is first loaded?
I have tried these things and others without much success:
- have an EventTrigger on "IsVisibleChanged" inside of grid1
- have an EventTrigger on "IsLoaded" inside of grid1
- have a PropertyChangedTrigger for the visibility of grid1 inside of the root grid
Is there a good way of updating focus with the states of the VisualStateManager or at least to correct the focus in response to the visual state changing?
Code: Select all
<Grid x:Name"root">
<VisualStateManager.VisualStateGroups>
<!-- Multiple states where grid1 visibility is set to either Visible or Collapsed -->
</VisualStateManager.VisualStateGroups>
<Grid x:Name"grid1">
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
<Button Content="First Button"/>
<Expander x:Name="expand" Header="Expander" IsExpanded="True">
</Expander>
<Button Content="Second Button"/>
</StackPanel>
</Grid>
<Grid x:Name"grid2">
<!-- Other Content -->
</Grid>
</Grid>
-
sfernandez
Site Admin
- Posts: 3134
- Joined:
Re: Setting Focus Directly to Expander Button
Hello, if you have some visual states that handle the visibility of some parts of the UI, and you want to change the focus after going to any of those states, you can wait for the state animation to finish and then set the focus. See this example:
Is this what you're looking for?
Code: Select all
<Grid
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:b="http://schemas.microsoft.com/xaml/behaviors"
xmlns:noesis="clr-namespace:NoesisGUIExtensions;assembly=Noesis.GUI.Extensions"
x:Name="rootGrid">
<b:Interaction.Triggers>
<b:EventTrigger EventName="Loaded">
<b:GoToStateAction TargetName="rootGrid" StateName="ShowGrid1"/>
</b:EventTrigger>
<b:StoryboardCompletedTrigger Storyboard="{Binding Storyboard, ElementName=ShowGrid1}">
<noesis:SetFocusAction TargetName="expand"/>
<noesis:MoveFocusAction Direction="Down"/>
</b:StoryboardCompletedTrigger>
<b:StoryboardCompletedTrigger Storyboard="{Binding Storyboard, ElementName=ShowGrid2}">
<noesis:SetFocusAction TargetName="btn"/>
</b:StoryboardCompletedTrigger>
</b:Interaction.Triggers>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="ScreenStates">
<VisualState x:Name="ShowGrid1">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="grid1" Storyboard.TargetProperty="Visibility">
<DiscreteObjectKeyFrame KeyTime="0" Value="{x:Static Visibility.Visible}"/>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="grid2" Storyboard.TargetProperty="Visibility">
<DiscreteObjectKeyFrame KeyTime="0" Value="{x:Static Visibility.Collapsed}"/>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="ShowGrid2">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="grid2" Storyboard.TargetProperty="Visibility">
<DiscreteObjectKeyFrame KeyTime="0" Value="{x:Static Visibility.Visible}"/>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="grid1" Storyboard.TargetProperty="Visibility">
<DiscreteObjectKeyFrame KeyTime="0" Value="{x:Static Visibility.Collapsed}"/>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Grid x:Name="grid1">
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
<Button Content="ButtonA"/>
<Expander x:Name="expand" Header="Expander" IsExpanded="True">
<Ellipse Height="200" Fill="Red"/>
</Expander>
<Button Content="ButtonB">
<b:Interaction.Triggers>
<b:EventTrigger EventName="Click">
<b:GoToStateAction TargetName="rootGrid" StateName="ShowGrid2"/>
</b:EventTrigger>
</b:Interaction.Triggers>
</Button>
</StackPanel>
</Grid>
<Grid x:Name="grid2">
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
<Button x:Name="btn" Content="ButtonC"/>
<Button Content="ButtonD"/>
<Button Content="ButtonE">
<b:Interaction.Triggers>
<b:EventTrigger EventName="Click">
<b:GoToStateAction TargetName="rootGrid" StateName="ShowGrid1"/>
</b:EventTrigger>
</b:Interaction.Triggers>
</Button>
</StackPanel>
</Grid>
</Grid>
Re: Setting Focus Directly to Expander Button
Yes! This is exactly it! Focus navigation seems to be working perfectly now.
Thank you!!
Thank you!!
Re: Setting Focus Directly to Expander Button
Great! Marking this as solved
Who is online
Users browsing this forum: Ahrefs [Bot], Bing [Bot] and 1 guest