Observação
O acesso a essa página exige autorização. Você pode tentar entrar ou alterar diretórios.
O acesso a essa página exige autorização. Você pode tentar alterar os diretórios.
Para mover o foco programaticamente em seu aplicativo windows, você pode usar o método FocusManager.TryMoveFocus ou o método FindNextElement .
TryMoveFocus tenta alterar o foco do elemento com foco para o próximo elemento focalizável na direção especificada, enquanto FindNextElement recupera o elemento (como DependencyObject) que receberá foco com base na direção de navegação especificada (somente navegação direcional, não pode ser usado para emular a navegação de guia).
Observação
É recomendável usar o método FindNextElement em vez de FindNextFocusableElement porque FindNextFocusableElement recupera um UIElement, que retorna nulo se o próximo elemento focalizável não for um UIElement (como um objeto Hyperlink).
Localizar um candidato de foco dentro de um escopo
Você pode personalizar o comportamento de navegação de foco para TryMoveFocus e FindNextElement, incluindo a pesquisa do próximo candidato de foco em uma árvore de interface do usuário específica ou a exclusão de elementos específicos da consideração.
Este exemplo usa um jogo TicTacToe para demonstrar os métodos TryMoveFocus e FindNextElement .
<StackPanel Orientation="Horizontal"
VerticalAlignment="Center"
HorizontalAlignment="Center" >
<Button Content="Start Game" />
<Button Content="Undo Movement" />
<Grid x:Name="TicTacToeGrid" KeyDown="OnKeyDown">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="50" />
<ColumnDefinition Width="50" />
<ColumnDefinition Width="50" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="50" />
<RowDefinition Height="50" />
<RowDefinition Height="50" />
</Grid.RowDefinitions>
<myControls:TicTacToeCell
Grid.Column="0" Grid.Row="0"
x:Name="Cell00" />
<myControls:TicTacToeCell
Grid.Column="1" Grid.Row="0"
x:Name="Cell10"/>
<myControls:TicTacToeCell
Grid.Column="2" Grid.Row="0"
x:Name="Cell20"/>
<myControls:TicTacToeCell
Grid.Column="0" Grid.Row="1"
x:Name="Cell01"/>
<myControls:TicTacToeCell
Grid.Column="1" Grid.Row="1"
x:Name="Cell11"/>
<myControls:TicTacToeCell
Grid.Column="2" Grid.Row="1"
x:Name="Cell21"/>
<myControls:TicTacToeCell
Grid.Column="0" Grid.Row="2"
x:Name="Cell02"/>
<myControls:TicTacToeCell
Grid.Column="1" Grid.Row="2"
x:Name="Cell22"/>
<myControls:TicTacToeCell
Grid.Column="2" Grid.Row="2"
x:Name="Cell32"/>
</Grid>
</StackPanel>
private void OnKeyDown(object sender, KeyRoutedEventArgs e)
{
DependencyObject candidate = null;
var options = new FindNextElementOptions ()
{
SearchRoot = TicTacToeGrid,
XYFocusNavigationStrategyOverride = XYFocusNavigationStrategyOverride.Projection
};
switch (e.Key)
{
case Windows.System.VirtualKey.Up:
candidate =
FocusManager.FindNextElement(
FocusNavigationDirection.Up, options);
break;
case Windows.System.VirtualKey.Down:
candidate =
FocusManager.FindNextElement(
FocusNavigationDirection.Down, options);
break;
case Windows.System.VirtualKey.Left:
candidate = FocusManager.FindNextElement(
FocusNavigationDirection.Left, options);
break;
case Windows.System.VirtualKey.Right:
candidate =
FocusManager.FindNextElement(
FocusNavigationDirection.Right, options);
break;
}
// Also consider whether candidate is a Hyperlink, WebView, or TextBlock.
if (candidate != null && candidate is Control)
{
(candidate as Control).Focus(FocusState.Keyboard);
}
}
Use FindNextElementOptions para personalizar ainda mais como os candidatos de foco são identificados. Este objeto fornece as seguintes propriedades:
- SearchRoot – Limitar a pesquisa de candidatos à navegação de foco aos filhos deste DependencyObject. Nulo indica que a pesquisa deve iniciar a partir da raiz da árvore visual.
Importante
Se uma ou mais transformações forem aplicadas aos descendentes de SearchRoot que as colocam fora da área direcional, esses elementos ainda serão considerados candidatos.
- ExclusionRect – Os candidatos à navegação de foco são identificados usando um retângulo delimitador "fictício", em que todos os objetos sobrepostos são excluídos do foco de navegação. Esse retângulo é usado apenas para cálculos e nunca é adicionado à árvore visual.
- HintRect – Os candidatos à navegação de foco são identificados usando um retângulo delimitador "fictício" que identifica os elementos mais propensos a receber o foco. Esse retângulo é usado apenas para cálculos e nunca é adicionado à árvore visual.
- XYFocusNavigationStrategyOverride – A estratégia de navegação de foco usada para identificar o elemento mais adequado para receber o foco.
A imagem a seguir ilustra alguns desses conceitos.
Quando o elemento B tem foco, FindNextElement identifica eu como o candidato de foco ao navegar para a direita. Os motivos para isso são:
- Devido ao HintRect em A, a referência inicial é A, não B
- C não é um candidato porque MyPanel foi especificado como SearchRoot
- F não é um candidato porque o ExclusionRect se sobrepõe a ele
Comportamento personalizado de navegação por foco usando dicas de navegação
Eventos de foco de navegação
Evento NoFocusCandidateFound
O evento UIElement.NoFocusCandidateFound é acionado quando as teclas tab ou seta são pressionadas e não há nenhum candidato de foco na direção especificada. Este evento não é disparado para TryMoveFocus.
Como esse é um evento roteado, ele se propaga do elemento focado através de objetos pai sucessivos até a raiz da árvore de objetos. Isso permite que você lide com o evento sempre que apropriado.
Aqui, mostramos como um Grid abre um SplitView quando o usuário tenta mover o foco para a esquerda do controle mais à esquerda que pode ser focado (consulte Designing for Xbox and TV).
<Grid NoFocusCandidateFound="OnNoFocusCandidateFound">
...
</Grid>
private void OnNoFocusCandidateFound (
UIElement sender, NoFocusCandidateFoundEventArgs args)
{
if(args.NavigationDirection == FocusNavigationDirection.Left)
{
if(args.InputDevice == FocusInputDeviceKind.Keyboard ||
args.InputDevice == FocusInputDeviceKind.GameController )
{
OpenSplitPaneView();
}
args.Handled = true;
}
}
Eventos GotFocus e LostFocus
Os eventos UIElement.GotFocus e UIElement.LostFocus são acionados quando um elemento obtém o foco ou perde o foco, respectivamente. Este evento não é disparado para TryMoveFocus.
Como esses são eventos roteados, eles se propagam do elemento focado através de objetos pai sucessivos até chegar à raiz da árvore de objetos. Isso permite que você trate do evento quando apropriado.
Eventos GettingFocus e LosingFocus
Os eventos UIElement.GettingFocus e UIElement.LosingFocus são acionados antes dos respectivos eventos UIElement.GotFocus e UIElement.LostFocus .
Como esses são eventos roteados, eles se propagam do elemento focado através dos objetos pai sucessivos até a raiz da árvore de objetos. Como isso acontece antes que uma alteração de foco ocorra, você pode redirecionar ou cancelar a alteração de foco.
GettingFocus e LosingFocus são eventos síncronos, portanto, o foco não será movido enquanto esses eventos estiverem borbulhando. No entanto, GotFocus e LostFocus são eventos assíncronos, o que significa que não há garantia de que o foco não se moverá novamente antes que o manipulador seja executado.
Se o foco passar por uma chamada para Control.Focus, GettingFocus será gerado durante a chamada, enquanto GotFocus será acionado após a chamada.
O destino de navegação de foco pode ser alterado durante os eventos GettingFocus e LosingFocus (antes que o foco se mova) por meio da propriedade GettingFocusEventArgs.NewFocusedElement . Mesmo que o destino seja alterado, o evento ainda assim continua a se propagar, e o destino pode ser alterado novamente.
Para evitar problemas de reentração, uma exceção será gerada se você tentar mover o foco (usando TryMoveFocus ou Control.Focus) enquanto esses eventos estiverem borbulhando.
Esses eventos são acionados independentemente do motivo da movimentação do foco (incluindo navegação de guia, navegação direcional e navegação programática).
Esta é a ordem de execução para os eventos de foco:
- LosingFocus Se o foco for redefinido de volta para o elemento de foco perdido ou TryCancel for bem-sucedido, nenhum evento adicional será disparado.
- GettingFocus Se o foco for redefinido de volta para o elemento que perdeu o foco ou se TryCancel for bem-sucedido, nenhum evento adicional será disparado.
- LostFocus
- GotFocus
A imagem a seguir mostra como, ao mover para a direita de A, o XYFocus escolhe B4 como um candidato. B4, em seguida, aciona o evento GettingFocus em que o ListView tem a oportunidade de reatribuir o foco para B3.
Alterar o destino de navegação de foco no evento GettingFocus
Aqui, mostramos como tratar o evento GettingFocus e redirecionar o foco.
<StackPanel Orientation="Horizontal">
<Button Content="A" />
<ListView x:Name="MyListView" SelectedIndex="2" GettingFocus="OnGettingFocus">
<ListViewItem>LV1</ListViewItem>
<ListViewItem>LV2</ListViewItem>
<ListViewItem>LV3</ListViewItem>
<ListViewItem>LV4</ListViewItem>
<ListViewItem>LV5</ListViewItem>
</ListView>
</StackPanel>
private void OnGettingFocus(UIElement sender, GettingFocusEventArgs args)
{
//Redirect the focus only when the focus comes from outside of the ListView.
// move the focus to the selected item
if (MyListView.SelectedIndex != -1 &&
IsNotAChildOf(MyListView, args.OldFocusedElement))
{
var selectedContainer =
MyListView.ContainerFromItem(MyListView.SelectedItem);
if (args.FocusState ==
FocusState.Keyboard &&
args.NewFocusedElement != selectedContainer)
{
args.TryRedirect(
MyListView.ContainerFromItem(MyListView.SelectedItem));
args.Handled = true;
}
}
}
Aqui, mostramos como lidar com o evento LosingFocus para um CommandBar e definir o foco quando o menu for fechado.
<CommandBar x:Name="MyCommandBar" LosingFocus="OnLosingFocus">
<AppBarButton Icon="Back" Label="Back" />
<AppBarButton Icon="Stop" Label="Stop" />
<AppBarButton Icon="Play" Label="Play" />
<AppBarButton Icon="Forward" Label="Forward" />
<CommandBar.SecondaryCommands>
<AppBarButton Icon="Like" Label="Like" />
<AppBarButton Icon="Share" Label="Share" />
</CommandBar.SecondaryCommands>
</CommandBar>
private void OnLosingFocus(UIElement sender, LosingFocusEventArgs args)
{
if (MyCommandBar.IsOpen == true &&
IsNotAChildOf(MyCommandBar, args.NewFocusedElement))
{
if (args.TryCancel())
{
args.Handled = true;
}
}
}
Localizar o primeiro e o último elemento focalizável
Os métodos FocusManager.FindFirstFocusableElement e FocusManager.FindLastFocusableElement movem o foco para o primeiro ou o último elemento focalizável dentro do escopo de um objeto (a árvore de elementos de um UIElement ou a árvore de texto de um TextElement). O escopo é especificado na chamada (se o argumento for nulo, o escopo será a janela atual).
Se nenhum candidato de foco puder ser identificado no escopo, retorna-se nulo.
Aqui, mostramos como especificar que os botões de um CommandBar têm um comportamento direcional de encapsulamento (consulte Interações de Teclado).
<CommandBar x:Name="MyCommandBar" LosingFocus="OnLosingFocus">
<AppBarButton Icon="Back" Label="Back" />
<AppBarButton Icon="Stop" Label="Stop" />
<AppBarButton Icon="Play" Label="Play" />
<AppBarButton Icon="Forward" Label="Forward" />
<CommandBar.SecondaryCommands>
<AppBarButton Icon="Like" Label="Like" />
<AppBarButton Icon="ReShare" Label="Share" />
</CommandBar.SecondaryCommands>
</CommandBar>
private void OnLosingFocus(UIElement sender, LosingFocusEventArgs args)
{
if (IsNotAChildOf(MyCommandBar, args.NewFocussedElement))
{
DependencyObject candidate = null;
if (args.Direction == FocusNavigationDirection.Left)
{
candidate = FocusManager.FindLastFocusableElement(MyCommandBar);
}
else if (args.Direction == FocusNavigationDirection.Right)
{
candidate = FocusManager.FindFirstFocusableElement(MyCommandBar);
}
if (candidate != null)
{
args.NewFocusedElement = candidate;
args.Handled = true;
}
}
}
Artigos relacionados
Windows developer