Compartir a través de


Información general sobre comandos

El comando es un mecanismo de entrada en Windows Presentation Foundation (WPF) que proporciona control de entrada en un nivel más semántico que la entrada del dispositivo. Algunos ejemplos de comandos son las operaciones Copiar, Cortar y Pegar que se encuentran en muchas aplicaciones.

Esta información general define qué comandos hay en WPF, qué clases forman parte del modelo de comandos y cómo usar y crear comandos en las aplicaciones.

Este tema contiene las secciones siguientes:

Qué son los comandos

Los comandos tienen varios propósitos. El primer propósito es separar la semántica y el objeto que invoca un comando de la lógica que ejecuta el comando. Esto permite que varios orígenes y dispares invoquen la misma lógica de comandos y permite personalizar la lógica de comandos para distintos destinos. Por ejemplo, las operaciones de edición Copiar, Cortar y Pegar, que se encuentran en muchas aplicaciones, se pueden invocar mediante diferentes acciones de usuario si se implementan mediante comandos. Una aplicación puede permitir que un usuario corte objetos seleccionados o texto haciendo clic en un botón, eligiendo un elemento en un menú o usando una combinación de teclas, como CTRL+X. Mediante el uso de comandos, puede enlazar cada tipo de acción de usuario a la misma lógica.

Otro propósito de los comandos es indicar si hay una acción disponible. Para continuar con el ejemplo de cortar un objeto o texto, la acción solo tiene sentido cuando se selecciona algo. Si un usuario intenta cortar un objeto o texto sin tener nada seleccionado, no ocurrirá nada. Para indicar esto al usuario, muchas aplicaciones deshabilitan botones y elementos de menú para que el usuario sepa si es posible realizar una acción. Un comando puede indicar si una acción es posible mediante la implementación del CanExecute método . Un botón puede suscribirse al CanExecuteChanged evento y deshabilitarse si CanExecute devuelve false o se habilita si CanExecute devuelve true.

La semántica de un comando puede ser coherente en todas las aplicaciones y clases, pero la lógica de la acción es específica del objeto concreto en el que se actúa. La combinación de teclas CTRL+X invoca el comando Cortar en clases de texto, clases de imagen y exploradores web, pero la lógica real para realizar la operación Cortar se define mediante la aplicación que realiza el corte. Un RoutedCommand permite a los clientes implementar la lógica. Un objeto de texto puede cortar el texto seleccionado en el Portapapeles, mientras que un objeto de imagen puede cortar la imagen seleccionada. Cuando una aplicación controla el Executed evento, tiene acceso al destino del comando y puede realizar las acciones adecuadas en función del tipo de destino.

Ejemplo de comando simple en WPF

La manera más sencilla de usar un comando en WPF es usar una predefinida RoutedCommand de una de las clases de biblioteca de comandos; usar un control que tenga compatibilidad nativa para controlar el comando; y usar un control que tenga compatibilidad nativa para invocar un comando. El Paste comando es uno de los comandos predefinidos de la ApplicationCommands clase . El TextBox control tiene lógica integrada para controlar el Paste comando. Y la MenuItem clase tiene compatibilidad nativa para invocar comandos.

En el ejemplo siguiente se muestra cómo configurar un MenuItem para que, al hacer clic en él, invoque el comando Paste en un TextBox, suponiendo que el TextBox tiene el foco del 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

Cuatro conceptos principales en comandos de WPF

El modelo de comandos enrutado en WPF se puede dividir en cuatro conceptos principales: el comando, el origen del comando, el destino del comando y el enlace de comandos:

  • El comando es la acción que se va a ejecutar.

  • El origen del comando es el objeto que invoca el comando.

  • El destino del comando es el objeto en el que se ejecuta el comando.

  • El enlace de comandos es el objeto que asigna la lógica de comandos al comando.

En el ejemplo anterior, el Paste comando es el comando , MenuItem es el origen del comando , TextBox es el destino del comando y el enlace de comandos lo proporciona el TextBox control . Es importante señalar que no siempre sucede que el CommandBinding sea suministrado por el control que actúa como clase objetivo del comando. Con bastante frecuencia, el CommandBinding debe ser creado por el desarrollador de aplicaciones, o el CommandBinding podría estar asociado a un ancestro del destino de comando.

Órdenes

Los comandos de WPF se crean mediante la implementación de la ICommand interfaz . ICommand expone dos métodos, Execute, y CanExecute, y un evento , CanExecuteChanged. Execute realiza las acciones asociadas al comando . CanExecute determina si el comando puede ejecutarse en el destino de comando actual. CanExecuteChanged se genera si el administrador de comandos que centraliza las operaciones detecta un cambio en la fuente de comando que podría invalidar un comando que se ha generado pero que aún no ha sido ejecutado por el enlace de comandos. La implementación de WPF de ICommand es la clase RoutedCommand y es el foco de esta visión general.

Las fuentes principales de entrada en WPF son el ratón, el teclado, la tinta digital y los comandos enrutados. Las entradas más orientadas al dispositivo usan un RoutedEvent para notificar a los objetos de una página de aplicación que se ha producido un evento de entrada. A RoutedCommand no es diferente. Los métodos Execute y CanExecute de un RoutedCommand no contienen la lógica de aplicación para el comando; en cambio, procesan eventos enrutados que se transmiten y burbujean a través del árbol de elementos hasta que encuentran un objeto con un CommandBinding. El CommandBinding contiene los encargados de estos eventos y son ellos quienes ejecutan el comando. Para obtener más información sobre el enrutamiento de eventos en WPF, vea Información general sobre eventos enrutados.

El método Execute en un RoutedCommand genera los eventos PreviewExecuted y Executed en el destino del comando. El método CanExecute en un RoutedCommand genera los eventos CanExecute y PreviewCanExecute en el destino del comando. Estos eventos se moverán y burbujearán por el árbol de elementos hasta que encuentren un objeto que tenga un CommandBinding para ese comando en particular.

WPF proporciona un conjunto de comandos enrutados comunes distribuidos entre varias clases: MediaCommands, ApplicationCommands, NavigationCommands, ComponentCommandsy EditingCommands. Estas clases constan solo de los RoutedCommand objetos y no de la lógica de implementación del comando. La lógica de implementación es responsabilidad del objeto en el que se ejecuta el comando.

Orígenes de comandos

Un origen de comandos es el objeto que invoca el comando. Algunos ejemplos de orígenes de comandos son MenuItem, Buttony KeyGesture.

Los orígenes de comandos en WPF generalmente implementan la interfaz ICommandSource.

ICommandSource expone tres propiedades: Command, CommandTargety CommandParameter:

Las clases de WPF que implementan ICommandSource son ButtonBase, MenuItem, Hyperlinky InputBinding. ButtonBase, MenuIteme Hyperlink invocan un comando cuando se hace clic en ellos y un InputBinding invoca un comando cuando se realiza el InputGesture asociado a él.

En el ejemplo siguiente se muestra cómo usar un MenuItem en un ContextMenu como fuente de comando para el 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, un origen de comandos escuchará el evento CanExecuteChanged. Este evento informa al origen del comando que puede haber cambiado la capacidad del comando para ejecutarse en el destino de comando actual. El origen del comando puede consultar el estado actual de RoutedCommand mediante el CanExecute método . A continuación, el origen del comando puede deshabilitarse si el comando no se puede ejecutar. Un ejemplo de esto es un MenuItem que se desactiva visualmente cuando un comando no se puede ejecutar.

InputGesture Se puede usar como origen de comandos. Dos tipos de gestos de entrada en WPF son KeyGesture y MouseGesture. Puede considerar un KeyGesture como un método abreviado de teclado, como CTRL+C. Un KeyGesture consta de un Key y un conjunto de ModifierKeys. MouseGesture está compuesto por un MouseAction y un conjunto opcional de ModifierKeys.

Para que un InputGesture objeto actúe como origen de comandos, debe estar asociado a un comando. Hay varias maneras de lograrlo. Una manera es usar un InputBinding.

En el ejemplo siguiente se muestra cómo crear un KeyBinding entre un KeyGesture y un 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)

Otra manera de asociar un InputGesture a un RoutedCommand es agregar el InputGesture al InputGestureCollection en el RoutedCommand.

En el ejemplo siguiente se muestra cómo añadir un KeyGesture al InputGestureCollection de un 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

Un CommandBinding asocia un comando a los controladores de eventos que implementan el comando.

La CommandBinding clase contiene una Command propiedad, y PreviewExecuted, Executed, PreviewCanExecute y CanExecute eventos.

Command es el comando al que CommandBinding se está asociando . Los controladores de eventos que están asociados a los PreviewExecuted eventos y Executed implementan la lógica de comandos. Los controladores de eventos adjuntos a PreviewCanExecute y CanExecute determinan si el comando se puede ejecutar en el objetivo del comando actual.

En el ejemplo siguiente se muestra cómo crear un CommandBinding en la raíz Window de una aplicación. El CommandBinding asocia el Open comando con los controladores Executed y 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)

A continuación, se crean el ExecutedRoutedEventHandler y un CanExecuteRoutedEventHandler. ExecutedRoutedEventHandler abre un MessageBox que muestra una cadena que indica que se ha ejecutado el comando. CanExecuteRoutedEventHandler establece la propiedad CanExecute en 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

Un CommandBinding se adjunta a un objeto específico, como la raíz Window de la aplicación o un control. El objeto al que está adjunto CommandBinding define el ámbito de la vinculación. Por ejemplo, un CommandBinding adjunto a un antecesor del destino del comando puede ser alcanzado por el evento Executed, pero un CommandBinding adjunto a un descendiente del destino del comando no se puede alcanzar. Se trata de una consecuencia directa de la forma en que un RoutedEvent tunela y burbujea desde el objeto que genera el evento.

En algunas situaciones, CommandBinding se adjunta al destino del comando, como ocurre con la clase TextBox y los comandos Cut, Copy y Paste. Sin embargo, con bastante frecuencia, es más conveniente adjuntar el CommandBinding a un ancestro del destino de comando, como el objeto principal Window o el objeto Application, especialmente si se puede usar el mismo CommandBinding para varios destinos de comando. Estas son las decisiones de diseño que querrá tener en cuenta al crear la infraestructura de comandos.

Objetivo del comando

El destino del comando es el elemento en el que se ejecuta el comando. Con respecto a RoutedCommand, el destino del comando es el elemento en el que se inicia el enrutamiento de Executed y CanExecute. Como se indicó anteriormente, en WPF, la propiedad CommandTarget en ICommandSource solo es aplicable cuando ICommand es un RoutedCommand. Si el CommandTarget se establece en un ICommandSource y el comando correspondiente no es un RoutedCommand, se omite el destino del comando.

El origen del comando puede establecer explícitamente el destino del comando. Si no se define el destino del comando, el elemento con foco de teclado se usará como destino del comando. Una de las ventajas de usar el elemento con foco de teclado como destino del comando es que permite al desarrollador de aplicaciones usar el mismo origen de comandos para invocar un comando en varios destinos sin tener que realizar un seguimiento del destino de comando. Por ejemplo, si MenuItem invoca el comando Paste en una aplicación que tiene un TextBox control y un PasswordBox control, el destino puede ser el TextBox o el PasswordBox dependiendo del control que tenga el enfoque del teclado.

En el ejemplo siguiente se muestra cómo establecer explícitamente el destino del comando en el marcado y en el código subyacente.

<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

El Gestor de Comandos

CommandManager proporciona una serie de funciones relacionadas con comandos. Proporciona un conjunto de métodos estáticos para agregar y quitar PreviewExecuted, Executed, PreviewCanExecute y CanExecute controladores de eventos a y desde un elemento específico. Proporciona un medio para registrar CommandBinding objetos y InputBinding en una clase específica. CommandManager también proporciona un medio, a través del RequerySuggested evento, para notificar a un comando cuando debe generar el CanExecuteChanged evento.

El método InvalidateRequerySuggested fuerza a CommandManager a generar el evento RequerySuggested. Esto es útil para condiciones que deben deshabilitar o habilitar un comando, pero que no son condiciones conocidas por el CommandManager.

Biblioteca de comandos

WPF proporciona un conjunto de comandos predefinidos. La biblioteca de comandos consta de las siguientes clases: ApplicationCommands, NavigationCommands, MediaCommands, EditingCommandsy .ComponentCommands Estas clases proporcionan comandos como Cut, BrowseBack y BrowseForward, Play, Stopy Pause.

Muchos de estos comandos incluyen un conjunto de enlaces de entrada predeterminados. Por ejemplo, si especifica que la aplicación controla el comando de copia, obtendrá automáticamente el enlace de teclado "CTRL+C" También obtendrá enlaces para otros dispositivos de entrada, como gestos de lápiz de PC tableta e información de voz.

Al hacer referencia a comandos en las distintas bibliotecas de comandos mediante XAML, normalmente puedes omitir el nombre de clase de la clase de biblioteca que expone la propiedad de comando estático. Por lo general, los nombres de comando son inequívocas como cadenas y los tipos propietarios existen para proporcionar una agrupación lógica de comandos, pero no son necesarios para la desambiguación. Por ejemplo, puede especificar Command="Cut" en lugar del más extenso Command="ApplicationCommands.Cut". Este es un mecanismo conveniente integrado en el procesador XAML de WPF para comandos (más precisamente, es un comportamiento de convertidor de tipos de ICommand, al que hace referencia el procesador XAML de WPF en el momento de carga).

Creación de comandos personalizados

Si los comandos de las clases de biblioteca de comandos no satisfacen sus necesidades, puede crear sus propios comandos. Hay dos maneras de crear un comando personalizado. La primera consiste en empezar desde cero e implementar la ICommand interfaz. La otra manera, y el enfoque más común, es crear un RoutedCommand o un RoutedUICommand.

Para obtener un ejemplo de creación de un RoutedCommand personalizado, vea Crear un ejemplo de RoutedCommand personalizado.

Consulte también