Visão geral do comando
Comando é um mecanismo de entrada no WPF (Windows Presentation Foundation) que fornece tratamento de entrada em um nível mais semântico do que a entrada do dispositivo. Exemplos de comandos são as operações Copiar, Recortare Colar encontradas em muitos aplicativos.
Essa visão geral define quais comandos estão no WPF, quais classes fazem parte do modelo de comando e como usar e criar comandos em seus aplicativos.
Este tópico contém as seguintes seções:
O que são comandos
Os comandos têm várias finalidades. A primeira finalidade é separar a semântica e o objeto que invoca um comando da lógica que executa o comando. Isso permite que várias fontes diferentes invoquem a mesma lógica de comando e permite que a lógica de comando seja personalizada para destinos diferentes. Por exemplo, as operações de edição Copiar, Cortare Colar, que são encontradas em muitos aplicativos, podem ser invocadas usando diferentes ações do usuário se forem implementadas usando comandos. Um aplicativo pode permitir que um usuário corte objetos ou texto selecionados clicando em um botão, escolhendo um item em um menu ou usando uma combinação de chaves, como CTRL+X. Usando comandos, você pode associar cada tipo de ação do usuário à mesma lógica.
Outra finalidade dos comandos é indicar se uma ação está disponível. Para continuar o exemplo de corte de um objeto ou texto, a ação só faz sentido quando algo é selecionado. Se um usuário tentar cortar um objeto ou texto sem ter nada selecionado, nada acontecerá. Para indicar isso ao usuário, muitos aplicativos desabilitam botões e itens de menu para que o usuário saiba se é possível executar uma ação. Um comando pode indicar se uma ação é possível implementando o método CanExecute. Um botão pode se inscrever no evento CanExecuteChanged e ser desativado se CanExecute retornar false
ou ser ativado se CanExecute retornar true
.
A semântica de um comando pode ser consistente entre aplicativos e classes, mas a lógica da ação é específica para o objeto específico que foi agido. A combinação de teclas CTRL+X invoca o comando Recortar em classes de texto, classes de imagem e navegadores da Web, mas a lógica real para executar a operação Recortar é definida pelo aplicativo que executa o corte. Um RoutedCommand permite que os clientes implementem a lógica. Um objeto de texto pode recortar o texto selecionado para a área de transferência, enquanto um objeto de imagem pode recortar a imagem selecionada. Quando um aplicativo manipula o evento Executed, ele tem acesso ao destino do comando e pode tomar as medidas apropriadas dependendo do tipo do destino.
Exemplo de comando simples no WPF
A maneira mais simples de usar um comando no WPF é usar um RoutedCommand predefinido de uma das classes de biblioteca de comandos; use um controle que tenha suporte nativo para lidar com o comando; e use um controle que tenha suporte nativo para invocar um comando. O comando Paste é um dos comandos predefinidos na classe ApplicationCommands. O controle TextBox tem lógica interna para lidar com o comando Paste. E a classe MenuItem tem suporte nativo para invocar comandos.
O exemplo a seguir mostra como configurar um MenuItem para que, quando ele for clicado, ele invoque o comando Paste em um TextBox, supondo que o TextBox tenha o foco do teclado.
<StackPanel>
<Menu>
<MenuItem Command="ApplicationCommands.Paste" />
</Menu>
<TextBox />
</StackPanel>
// Creating the UI objects
StackPanel mainStackPanel = new StackPanel();
TextBox pasteTextBox = new TextBox();
Menu stackPanelMenu = new Menu();
MenuItem pasteMenuItem = new MenuItem();
// Adding objects to the panel and the menu
stackPanelMenu.Items.Add(pasteMenuItem);
mainStackPanel.Children.Add(stackPanelMenu);
mainStackPanel.Children.Add(pasteTextBox);
// Setting the command to the Paste command
pasteMenuItem.Command = ApplicationCommands.Paste;
// Setting the command target to the TextBox
pasteMenuItem.CommandTarget = pasteTextBox;
' Creating the UI objects
Dim mainStackPanel As New StackPanel()
Dim pasteTextBox As New TextBox()
Dim stackPanelMenu As New Menu()
Dim pasteMenuItem As New MenuItem()
' Adding objects to the panel and the menu
stackPanelMenu.Items.Add(pasteMenuItem)
mainStackPanel.Children.Add(stackPanelMenu)
mainStackPanel.Children.Add(pasteTextBox)
' Setting the command to the Paste command
pasteMenuItem.Command = ApplicationCommands.Paste
Quatro conceitos principais no comando do WPF
O modelo de comando roteado no WPF pode ser dividido em quatro conceitos principais: o comando, a origem do comando, o destino do comando e a associação de comando:
O comando é a ação a ser executada.
A origem do comando é o objeto que invoca o comando.
O destino do comando é o objeto no qual o comando está sendo executado.
A associação do comando é o objeto que mapeia a lógica do comando ao comando.
No exemplo anterior, o comando Paste é o comando, o MenuItem é a origem do comando, o TextBox é o destino do comando e a associação de comando é fornecida pelo controle TextBox. Vale a pena observar que nem sempre o CommandBinding é fornecido pelo controle que serve como classe de destino do comando. Geralmente, o CommandBinding deve ser criado pelo desenvolvedor de aplicativos ou o CommandBinding pode estar anexado a um ancestral do destino de comando.
Comandos
Os comandos no WPF são criados implementando a interface ICommand. ICommand expõe dois métodos, Executee CanExecutee um evento, CanExecuteChanged. Execute executa as ações associadas ao comando. CanExecute determina se o comando pode ser executado no destino de comando atual. CanExecuteChanged será gerado se o gerenciador de comandos que centraliza as operações de comando detectar uma alteração na origem do comando que pode invalidar um comando que foi gerado, mas ainda não executado pela associação de comando. A implementação do WPF de ICommand é a classe RoutedCommand e constitui o foco desta visão geral.
As principais formas de entrada do WPF são o mouse, o teclado, a tinta e os comandos roteados. As entradas mais orientadas ao dispositivo usam um RoutedEvent para notificar objetos em uma página de aplicativo de que ocorreu um evento de entrada. Um RoutedCommand não é diferente. Os métodos Execute e CanExecute de um RoutedCommand não contêm a lógica da aplicação para o comando, mas sim disparam eventos roteados que canalizam e se propagam pela árvore de elementos até encontrarem um objeto com um CommandBinding. O CommandBinding contém os manipuladores desses eventos e são os manipuladores que executam o comando. Para obter mais informações sobre o roteamento de eventos no WPF, consulte Visão Geral de Eventos Roteados.
O método Execute em um RoutedCommand gera os eventos PreviewExecuted e Executed no destino de comando. O método CanExecute em um RoutedCommand gera os eventos CanExecute e PreviewCanExecute no destino de comando. Esses eventos se propagam e borbulham pela árvore de elementos até encontrarem um objeto que possui um CommandBinding para esse comando específico.
O WPF fornece um conjunto de comandos roteados comuns espalhados por várias classes: MediaCommands, ApplicationCommands, NavigationCommands, ComponentCommandse EditingCommands. Essas classes consistem apenas nos objetos RoutedCommand e não na lógica de implementação do comando. A lógica de implementação é responsabilidade do objeto no qual o comando está sendo executado.
Fontes de comando
Uma fonte de comando é o objeto que invoca o comando. Exemplos de fontes de comando são MenuItem, Buttone KeyGesture.
As fontes de comando no WPF geralmente implementam a interface ICommandSource.
ICommandSource expõe três propriedades: Command, CommandTargete CommandParameter:
Command é o comando a ser executado quando a origem do comando é invocada.
CommandTarget é o objeto no qual executar o comando. Vale a pena observar que, no WPF, a propriedade CommandTarget em ICommandSource só é aplicável quando o ICommand é um RoutedCommand. Se o CommandTarget estiver definido em um ICommandSource e o comando correspondente não for um RoutedCommand, o destino de comando será ignorado. Se o CommandTarget não estiver definido, o elemento com foco no teclado será o destino do comando.
CommandParameter é um tipo de dados definido pelo usuário usado para passar informações para os manipuladores que implementam o comando.
As classes do WPF que implementam ICommandSource são ButtonBase, MenuItem, Hyperlinke InputBinding. ButtonBase, MenuIteme Hyperlink invocam um comando quando são clicados e um InputBinding invoca um comando quando o InputGesture associado a ele é executado.
O exemplo a seguir mostra como usar um MenuItem em um ContextMenu como uma fonte de comando para o comando Properties.
<StackPanel>
<StackPanel.ContextMenu>
<ContextMenu>
<MenuItem Command="ApplicationCommands.Properties" />
</ContextMenu>
</StackPanel.ContextMenu>
</StackPanel>
StackPanel cmdSourcePanel = new StackPanel();
ContextMenu cmdSourceContextMenu = new ContextMenu();
MenuItem cmdSourceMenuItem = new MenuItem();
// Add ContextMenu to the StackPanel.
cmdSourcePanel.ContextMenu = cmdSourceContextMenu;
cmdSourcePanel.ContextMenu.Items.Add(cmdSourceMenuItem);
// Associate Command with MenuItem.
cmdSourceMenuItem.Command = ApplicationCommands.Properties;
Dim cmdSourcePanel As New StackPanel()
Dim cmdSourceContextMenu As New ContextMenu()
Dim cmdSourceMenuItem As New MenuItem()
' Add ContextMenu to the StackPanel.
cmdSourcePanel.ContextMenu = cmdSourceContextMenu
cmdSourcePanel.ContextMenu.Items.Add(cmdSourceMenuItem)
' Associate Command with MenuItem.
cmdSourceMenuItem.Command = ApplicationCommands.Properties
Normalmente, uma fonte de comando monitorará o evento CanExecuteChanged. Esse evento informa à origem do comando que a capacidade do comando de executar no destino de comando atual pode ter sido alterada. A origem do comando pode consultar o status atual do RoutedCommand usando o método CanExecute. A origem do comando pode se desabilitar se o comando não puder ser executado. Um exemplo disso é o MenuItem ficar esmaecido por si só quando um comando não puder ser executado.
Um InputGesture pode ser usado como uma fonte de comando. Dois tipos de gestos de entrada no WPF são o KeyGesture e MouseGesture. Você pode pensar em um KeyGesture como um atalho de teclado, como CTRL+C. Um KeyGesture é composto por um Key e um conjunto de ModifierKeys. Um MouseGesture é composto por um MouseAction e um conjunto opcional de ModifierKeys.
Para que um InputGesture atue como uma fonte de comando, ele deve ser associado a um comando. Há algumas maneiras de fazer isso. Uma maneira é usar um InputBinding.
O exemplo a seguir mostra como criar uma KeyBinding entre um KeyGesture e um RoutedCommand.
<Window.InputBindings>
<KeyBinding Key="B"
Modifiers="Control"
Command="ApplicationCommands.Open" />
</Window.InputBindings>
KeyGesture OpenKeyGesture = new KeyGesture(
Key.B,
ModifierKeys.Control);
KeyBinding OpenCmdKeybinding = new KeyBinding(
ApplicationCommands.Open,
OpenKeyGesture);
this.InputBindings.Add(OpenCmdKeybinding);
Dim OpenKeyGesture As New KeyGesture(Key.B, ModifierKeys.Control)
Dim OpenCmdKeybinding As New KeyBinding(ApplicationCommands.Open, OpenKeyGesture)
Me.InputBindings.Add(OpenCmdKeybinding)
Outra maneira de associar um InputGesture a um RoutedCommand é adicionar o InputGesture ao InputGestureCollection no RoutedCommand.
O exemplo a seguir mostra como adicionar um KeyGesture à InputGestureCollection de um RoutedCommand.
KeyGesture OpenCmdKeyGesture = new KeyGesture(
Key.B,
ModifierKeys.Control);
ApplicationCommands.Open.InputGestures.Add(OpenCmdKeyGesture);
Dim OpenCmdKeyGesture As New KeyGesture(Key.B, ModifierKeys.Control)
ApplicationCommands.Open.InputGestures.Add(OpenCmdKeyGesture)
CommandBinding
Um CommandBinding associa um comando aos manipuladores de eventos que implementam o comando.
A classe CommandBinding contém uma propriedade Command e eventos PreviewExecuted, Executed, PreviewCanExecutee CanExecute.
Command é o comando ao qual o CommandBinding está sendo associado. Os manipuladores de eventos anexados aos eventos PreviewExecuted e Executed implementam a lógica de comando. Os manipuladores de eventos anexados aos eventos PreviewCanExecute e CanExecute determinam se o comando pode ser executado no destino de comando atual.
O exemplo a seguir mostra como criar um CommandBinding na raiz Window de um aplicativo. O CommandBinding associa o comando Open a manipuladores Executed e CanExecute.
<Window.CommandBindings>
<CommandBinding Command="ApplicationCommands.Open"
Executed="OpenCmdExecuted"
CanExecute="OpenCmdCanExecute"/>
</Window.CommandBindings>
// Creating CommandBinding and attaching an Executed and CanExecute handler
CommandBinding OpenCmdBinding = new CommandBinding(
ApplicationCommands.Open,
OpenCmdExecuted,
OpenCmdCanExecute);
this.CommandBindings.Add(OpenCmdBinding);
' Creating CommandBinding and attaching an Executed and CanExecute handler
Dim OpenCmdBinding As New CommandBinding(ApplicationCommands.Open, AddressOf OpenCmdExecuted, AddressOf OpenCmdCanExecute)
Me.CommandBindings.Add(OpenCmdBinding)
Em seguida, o ExecutedRoutedEventHandler e um CanExecuteRoutedEventHandler são criados. O ExecutedRoutedEventHandler abre um MessageBox que exibe uma cadeia de caracteres dizendo que o comando foi executado. O CanExecuteRoutedEventHandler define a propriedade CanExecute como true
.
void OpenCmdExecuted(object target, ExecutedRoutedEventArgs e)
{
String command, targetobj;
command = ((RoutedCommand)e.Command).Name;
targetobj = ((FrameworkElement)target).Name;
MessageBox.Show("The " + command + " command has been invoked on target object " + targetobj);
}
Private Sub OpenCmdExecuted(ByVal sender As Object, ByVal e As ExecutedRoutedEventArgs)
Dim command, targetobj As String
command = CType(e.Command, RoutedCommand).Name
targetobj = CType(sender, FrameworkElement).Name
MessageBox.Show("The " + command + " command has been invoked on target object " + targetobj)
End Sub
void OpenCmdCanExecute(object sender, CanExecuteRoutedEventArgs e)
{
e.CanExecute = true;
}
Private Sub OpenCmdCanExecute(ByVal sender As Object, ByVal e As CanExecuteRoutedEventArgs)
e.CanExecute = True
End Sub
Um CommandBinding é anexado a um objeto específico, como o Window raiz do aplicativo ou um controle. O objeto ao qual o CommandBinding está anexado define o escopo da associação. Por exemplo, um CommandBinding anexado a um ancestral do destino de comando pode ser alcançado pelo evento Executed, mas um CommandBinding anexado a um descendente do destino de comando não pode ser atingido. Isso é uma consequência direta da maneira como um RoutedEvent se propaga e transita do objeto que aciona o evento.
Em algumas situações, o CommandBinding é anexado diretamente ao alvo do comando, como acontece com a classe TextBox e os comandos Cut, Copye Paste. Geralmente, porém, é mais conveniente anexar o CommandBinding a um ancestral do destino de comando, como o Window principal ou o objeto Application, especialmente se o mesmo CommandBinding puder ser usado para vários destinos de comando. Essas são decisões de design que você desejará considerar ao criar sua infraestrutura de comando.
Destino de comando
O destino de comando é o elemento no qual o comando é executado. Em relação a um RoutedCommand, o alvo do comando é o elemento no qual o roteamento do Executed e do CanExecute é iniciado. Conforme observado anteriormente, no WPF, a propriedade CommandTarget em ICommandSource só é aplicável quando o ICommand é um RoutedCommand. Se o CommandTarget estiver definido em um ICommandSource e o comando correspondente não for um RoutedCommand, o destino de comando será ignorado.
A origem do comando pode definir explicitamente o destino do comando. Se o destino de comando não estiver definido, o elemento com foco no teclado será usado como o destino do comando. Um dos benefícios de usar o elemento com foco no teclado como destino de comando é que ele permite que o desenvolvedor de aplicativos use a mesma origem de comando para invocar um comando em vários destinos sem precisar controlar o destino do comando. Por exemplo, se um MenuItem invocar o comando Colar em um aplicativo que tenha um controle TextBox e um controle PasswordBox, o destino poderá ser o TextBox ou PasswordBox dependendo de qual controle tem o foco do teclado.
O exemplo a seguir mostra como definir explicitamente o destino de comando na marcação e no código subjacente.
<StackPanel>
<Menu>
<MenuItem Command="ApplicationCommands.Paste"
CommandTarget="{Binding ElementName=mainTextBox}" />
</Menu>
<TextBox Name="mainTextBox"/>
</StackPanel>
// Creating the UI objects
StackPanel mainStackPanel = new StackPanel();
TextBox pasteTextBox = new TextBox();
Menu stackPanelMenu = new Menu();
MenuItem pasteMenuItem = new MenuItem();
// Adding objects to the panel and the menu
stackPanelMenu.Items.Add(pasteMenuItem);
mainStackPanel.Children.Add(stackPanelMenu);
mainStackPanel.Children.Add(pasteTextBox);
// Setting the command to the Paste command
pasteMenuItem.Command = ApplicationCommands.Paste;
// Setting the command target to the TextBox
pasteMenuItem.CommandTarget = pasteTextBox;
' Creating the UI objects
Dim mainStackPanel As New StackPanel()
Dim pasteTextBox As New TextBox()
Dim stackPanelMenu As New Menu()
Dim pasteMenuItem As New MenuItem()
' Adding objects to the panel and the menu
stackPanelMenu.Items.Add(pasteMenuItem)
mainStackPanel.Children.Add(stackPanelMenu)
mainStackPanel.Children.Add(pasteTextBox)
' Setting the command to the Paste command
pasteMenuItem.Command = ApplicationCommands.Paste
O Gerenciador de Comandos
O CommandManager atende a várias funções relacionadas a comandos. Ele fornece um conjunto de métodos estáticos para adicionar e remover manipuladores de eventos PreviewExecuted, Executed, PreviewCanExecutee CanExecute para e de um elemento específico. Ele fornece um meio de registrar CommandBinding e InputBinding objetos em uma classe específica. O CommandManager também fornece um meio, por meio do evento RequerySuggested, para notificar um comando quando ele deve gerar o evento CanExecuteChanged.
O método InvalidateRequerySuggested força o CommandManager a gerar o evento RequerySuggested. Isso é útil para condições que devem desabilitar/habilitar um comando, mas não são condições que o CommandManager está ciente.
Biblioteca de comandos
O WPF fornece um conjunto de comandos predefinidos. A biblioteca de comandos consiste nas seguintes classes: ApplicationCommands, NavigationCommands, MediaCommands, EditingCommandse o ComponentCommands. Essas classes fornecem comandos como Cut, BrowseBack e BrowseForward, Play, Stope Pause.
Muitos desses comandos incluem um conjunto de associações de entrada padrão. Por exemplo, se você especificar que seu aplicativo manipula o comando de cópia, você obtém automaticamente a associação de teclado "CTRL+C" Você também obtém associações para outros dispositivos de entrada, como gestos de caneta tablet PC e informações de fala.
Quando você faz referência a comandos nas várias bibliotecas de comandos usando XAML, geralmente pode omitir o nome da classe de biblioteca que expõe a propriedade de comando estático. Geralmente, os nomes de comando são inequívocas como cadeias de caracteres e os tipos proprietários existem para fornecer um agrupamento lógico de comandos, mas não são necessários para a desambiguação. Por exemplo, você pode especificar Command="Cut"
em vez do Command="ApplicationCommands.Cut"
mais verboso. Esse é um mecanismo de conveniência integrado ao processador XAML do WPF para comandos (mais precisamente, é um comportamento de conversor de tipo de ICommand, que é referenciado pelo processador XAML do WPF durante o carregamento).
Criando comandos personalizados
Se os comandos nas classes de biblioteca de comandos não atenderem às suas necessidades, você poderá criar seus próprios comandos. Há duas maneiras de criar um comando personalizado. A primeira é começar do zero e implementar a interface ICommand. A outra maneira e a abordagem mais comum é criar um RoutedCommand ou um RoutedUICommand.
Para obter um exemplo de criação de um RoutedCommandpersonalizado, consulte Criar umde exemplo RoutedCommand personalizado.
Consulte também
- RoutedCommand
- CommandBinding
- InputBinding
- CommandManager
- Visão Geral de Entrada
- Visão geral dos eventos roteados
- Implementar ICommandSource
- Como adicionar um comando a um menuItem
- Criar um Exemplo de RoutedCommand Personalizado
.NET Desktop feedback