Nota
O acesso a esta página requer autorização. Podes tentar iniciar sessão ou mudar de diretório.
O acesso a esta página requer autorização. Podes tentar mudar de diretório.
Para mover o foco programaticamente na sua aplicação Windows, pode usar o método FocusManager.TryMoveFocus ou o método FindNextElement .
O TryMoveFocus tenta mudar o foco do elemento com foco para o próximo elemento focalizável na direção especificada, enquanto o FindNextElement recupera o elemento (como um DependencyObject) que receberá o foco com base na direção de navegação especificada (apenas navegação direcional, não pode ser usado para emular a navegação por separador).
Observação
Recomendamos usar o método FindNextElement em vez do FindNextFocusableElement porque o FindNextFocusableElement recupera um UIElement, que devolve nulo se o próximo elemento focalizável não for um UIElement (como um objeto Hyperlink).
Encontre um candidato de foco dentro de um âmbito
Pode personalizar o comportamento de navegação de foco tanto para o TryMoveFocus como para o FindNextElement, incluindo procurar o próximo candidato a foco dentro de uma árvore de interface específica ou excluir elementos específicos da consideração.
Este exemplo utiliza um jogo de 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 a forma como os candidatos de foco são identificados. Este objeto fornece as seguintes propriedades:
- SearchRoot - Limitar a pesquisa de candidatos para navegação de foco aos filhos deste DependencyObject. Nulo indica iniciar a pesquisa na árvore visual a partir da raiz.
Importante
Se uma ou mais transformações forem aplicadas aos descendentes do SearchRoot que os colocam fora da área direcional, estes elementos continuam a ser considerados candidatos.
- ExclusionRect - Candidatos à navegação de foco são identificados usando um "retângulo de delimitação fictício" onde todos os objetos sobrepostos são excluídos do foco de navegação. Este 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 indica os elementos mais propensos a receber foco. Este 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 melhor elemento destinatário do foco.
A imagem seguinte ilustra alguns destes conceitos.
Quando o elemento B tem foco, FindNextElement identifica I como candidato a foco ao navegar para a direita. As razões para isto são:
- Devido ao HintRect em A, a referência inicial é A, não B
- C não é candidato porque o MyPanel foi especificado como o SearchRoot
- F não é candidato porque o ExclusionRect sobrepõe-se a ele
Comportamento personalizado de navegação com foco usando dicas de navegação
Eventos de foco na navegação
Evento NoFocusCandidateFound
O evento UIElement.NoFocusCandidateFound é ativado quando as teclas tab ou setas são pressionadas e não há candidato a foco na direção especificada. Este evento não é disparado para TryMoveFocus.
Como este é um evento encaminhado, ele propaga-se a partir do elemento focado, pelos objetos pais sucessivos, até à raiz da árvore de objetos. Isto permite-lhe gerir o evento sempre que for apropriado.
Aqui, mostramos como uma grelha abre um SplitView quando o utilizador tenta mover o foco para a esquerda do controlo mais à esquerda (ver Design para Xbox e 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 disparados quando um elemento recebe ou perde o foco, respetivamente. Este evento não é disparado para TryMoveFocus.
Como estes são eventos encaminhados, eles propagam-se do elemento focado por sucessivos objetos-pai até à raiz da árvore de objetos. Isto permite-lhe tratar o evento em qualquer local apropriado.
Eventos GettingFocus e LosingFocus
Os eventos UIElement.GettingFocus e UIElement.LosingFocus são ativados antes dos respetivos eventos UIElement.GotFocus e UIElement.LostFocus.
Como estes são eventos roteados, eles propagam-se do elemento em foco através de sucessivos objetos pais até à raiz da árvore de objetos. Como isto acontece antes de ocorrer uma mudança de foco, pode redirecionar ou cancelar a mudança de foco.
GettingFocus e LosingFocus são eventos síncronos, por isso o foco não será movido enquanto estes eventos estão a borbulhar. No entanto, GotFocus e LostFocus são eventos assíncronos, o que significa que não há garantia de que o focus não se mova novamente antes de o handler ser executado.
Se o foco se mover através de uma chamada para Control.Focus, GettingFocus é levantado durante a chamada, enquanto GotFocus é levantado após a chamada.
O alvo de navegação do foco pode ser alterado durante os eventos GettingFocus e LosingFocus (antes do movimento do foco) através da propriedade GettingFocusEventArgs.NewFocusedElement . Mesmo que o alvo seja alterado, o evento continua a propagar-se e o alvo pode ser alterado novamente.
Para evitar problemas de reentrada, é feita uma exceção se tentares mover o foco (usando TryMoveFocus ou Control.Focus) enquanto estes eventos estão a borbulhar.
Estes eventos são acionados independentemente do motivo da mudança de foco (incluindo navegação por guias, navegação direcional e navegação programática).
Aqui está a ordem de execução dos eventos de foco:
- Perder o Foco Se o foco for reiniciado para o elemento que perdeu o foco ou se TryCancel for bem-sucedido, não são lançados mais eventos.
- GettingFocus Se o foco for redefinido no elemento de perda de foco ou TryCancel for bem-sucedido, nenhum evento adicional é desencadeado.
- LostFocus
- GotFocus
A imagem seguinte mostra como, ao mover-se para a direita a partir de A, o XYFocus escolhe B4 como candidato. O B4 lança então o evento GettingFocus, onde o ListView tem a oportunidade de reatribuir o foco ao B3.
Alterar o alvo de navegação do foco no evento GettingFocus
Aqui, mostramos como lidar com 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 gerir o evento LosingFocus para uma Barra de Comandos e definir o foco quando o menu está 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;
}
}
}
Encontre o primeiro e o último elemento focável
Os métodos FocusManager.FindFirstFocusableElement e FocusManager.FindLastFocusableElement movem o foco para o primeiro ou último elemento focável dentro do âmbito de um objeto (a árvore de elementos de um UIElement ou a árvore de texto de um TextElement). O âmbito é especificado na chamada (se o argumento for nulo, o âmbito é a janela atual).
Se nenhum candidato de foco for identificado no âmbito, é retornado null.
Aqui, mostramos como especificar que os botões de uma Barra de Comandos têm um comportamento direcional envolvente (ver Interações com o 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