La Güeb de Joaquín

WPF

 

 

 

 

WPF - Commands

 

Sumario

Los comandos son un tipo especial de eventos. Son unos eventos abstractos y desacoplados de las interfaces de usuario. Reemplazan a los tradicionales eventos como el que se lanza cuando un usuario selecciona un elemento en una lista desplegable,  y  su característica más importante es que no están ligados a la interfaz de usuario que los expone.

 

Historial de este documento

Autor Joaquin Medina Serrano http://joaquin.medina.name/

Fechas importantes

·         Creación.: sábado 15/Febrero/2007

·         Modificación  jueves, 29 de enero de 2015

·         Impresión: jueves, 29 de enero de 2015/ 17:44

 

Palabras Clave

Commandos, Resources, command

 


 

 

1                  Contenido

1       WPF – Commands. 1

2.1         ¿Qué son los comandos?. 1

2.2         Cuatro conceptos básicos en los comandos WPF. 2

2.3         Comunicación entre [VievModel] y [Vista]. 2

2.4         Commands. 3

2.4.1          Clase DelegateCommand. 4

2.4.2          Ejemplo Un Command sin parámetros. 10

2.4.3          Ejemplo (1) Un Command Con parámetros. 12

2.4.4          Ejemplo (2) Un Command Con parámetros. 13

3       WPF – Comandos Predefinidos. 16

3.1         Comandos por defecto. 16

3.1.1          ApplicationCommands. 16

3.1.2          ComponentCommands. 16

3.1.3          MediaCommands. 16

3.1.4          NavigationCommands. 16

3.1.5          EditingCommands. 17

3.2         Uso de los Comandos desde XAML. 17

3.3         Referencia Bibliográfica. 18

 

 


 

 

1.1       ¿Qué son los comandos?

Los comandos son un tipo especial de eventos. Son unos eventos abstractos y desacoplados de las interfaces de usuario. Reemplazan a los tradicionales eventos como el que se lanza cuando un usuario selecciona un elemento en una lista desplegable,  y  su característica más importante es que no están ligados a la interfaz de usuario que los expone.

Mientras los eventos están enlazados a acciones de usuario, los comandos representan acciones independientes de la interfaz de usuario.

 (Algunos ejemplos de comandos son Cortar, Copiar y Pegar.)

 

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 lo ejecuta. Esto permite que varios orígenes dispares invoquen la misma lógica de comando y permite personalizar la lógica de comando para diferentes destinos. Por ejemplo, las operaciones de edición Copiar, Cortar y Pegar, que se encuentran en muchas aplicaciones, se pueden invocar mediante distintas acciones de usuario si se implementan con comandos. Una aplicación podría permitir a un usuario cortar texto u objetos seleccionados haciendo clic en un botón, eligiendo un elemento en un menú o utilizando una combinación de teclas, como CTRL+X. Mediante el uso de comandos, puede enlazar cada tipo de acción del usuario a la misma lógica.

·         Otro propósito de los comandos es indicar si una acción está disponible. Para continuar el ejemplo de cortar un objeto o texto, la acción tiene sentido sólo cuando algo está seleccionado. Si un usuario intenta cortar un objeto o texto sin tener algo seleccionado, no pasaría nada. Para indicar esto al usuario, muchas aplicaciones deshabilitan los botones y elementos de menú para que sepa si es posible realizar una acción. Un comando puede indicar si una acción es posible implementando el método CanExecute. Un botón puede suscribirse al evento CanExecuteChanged y estar deshabilitado si CanExecute devuelve false o estar habilitado si CanExecute devuelve true.

·         La semántica de un comando puede ser coherente entre aplicaciones y clases, pero la lógica de la acción es específica del objeto sobre 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 la define la aplicación que la realiza.

 

1.2       Cuatro conceptos básicos en los comandos WPF

El modelo de comando se puede descomponer en cuatro conceptos básicos: el comando, el origen del comando, el destino del comando y el enlace del comando:

Por ejemplo: Supongamos un menú edición con la operación Pegar, cuyo objeto es pegar un texto en un control TextBox:

·         [Commands] [El comando]. Es la acción que se va a ejecutar. (por ejemplo comando [Pegar]). El comando sabe en todo momento si la acción se puede realizar o no.

·         [Commnad Sources] [El origen del comando]. Es el objeto que invoca el comando. Por ejemplo un Botón, o un MenuItem [MenuItem / edición / pegar (paste)].

·         [Command Targets] [El destino del comando]. Es el objeto (un control es un objeto) donde se ejecuta el comando. Por ejemplo, el TextBox donde se pega el texto)

·         [Command Bindings] [El enlace del comando]. Es el objeto que contiene toda la lógica para la operación  a realizar. En el ejemplo que estoy poniendo, la toda la lógica necesaria para la operación ‘pegar’ está en el propio TextBox que recibe el texto pegado.

Una Observación: El objeto CommandBinding no siempre se suministra por el control (o la clase) de destino del comando. Con mucha frecuencia, el objeto CommandBinding debe ser creado por el desarrollador de la aplicación.

 

1.3       Comunicación entre [VievModel] y [Vista]

 

http://wphone.es/wp-content/uploads/2011/06/mvvm.jpg

En el patrón MVVM, las comunicaciones entre la Vista y el Modelo_Vista se hacen mediante Comandos y Notificaciones de eventos:

 

La [Vista] comunica con el [Modelo_Vista] de dos formas:

·         Con los enlaces de datos [Binding] ( que pueden ser bidireccionales y/o unidireccionales

·         Llamando a los comandos que define el [Modelo_Vista]

 

Por su parte el [Modelo_Vista] se comunica con SU [Vista]

·         Con los enlaces de datos [Binding] ( que pueden ser bidireccionales y/o unidireccionales

·         Disparando eventos [PropetyChanged]

 

Concretamente las clases [Modelo_Vista]:

·         Tienen que implementar la interfaz [InotifiPropetyChanged] para poder disparar el evento [PropetyChanged]. Esta implementación puede hacerse en cada una de las clases o bien crear una clase que encapsule toda la interfaz  y que sea heredada por cada [Modelo_Vista] que tengamos en nuestra aplicación.

·         Tiene que implementar Comandos para cada una de las acciones que necesite la [Vista]

·         A efectos de claridad de código, es conveniente que las clases [Modelo_Vista] hereden todas de una clase base.

 

1.4       Commands

Los comandos de WPF se crean mediante la implementación de la interfaz ICommand. Es decir, A bajo nivel, un comando es cualquier objeto que implemente la interfaz ICommand, la cual define tres (3) miembros:

·         Execute –  Realiza las acciones que están asociadas al comando. En general, llama a un  método que ejecuta la lógica del comando.

·         CanExecute – Determina si el comando se puede ejecutar en el destino del comando actual. En general es un método que devuelve true, si el comando está habilitado, false si esta deshabilitado.

·         CanExecuteChanged – Evento que se dispara si el valor de CanExecute cambia

Para crear un nuevo comando, solo debemos crear una nueva clase que implemente la interface ICommand (System.Windows.Input):

 

Public Class HelloCommand
    Implements ICommand
 
    Public Event CanExecuteChanged(sender As Object, e As EventArgs) _
                 Implements ICommand.CanExecuteChanged
 
    Public Function CanExecute(parameter As Object) As Boolean _
                    Implements ICommand.CanExecute
        RaiseEvent CanExecuteChanged(Me, EventArgs.Empty)
        Return True
    End Function
 
    Public Sub Execute(parameter As Object) _
                Implements ICommand.Execute
        MessageBox.Show("Hola")
    End Sub
End Class

 

1.4.1       Clase DelegateCommand

Cuando se trabaja con el patrón MVVM hay que escribir comandos para comunicar la vista con el [Modelo Vista], con lo que aparece un montón de código repetido. Un tal [Josh Smith] ha diseñado una clase a la que ha llamado [RelayCommand] que implementa la interfaz ICommand y se usa desde el [Modelo Vista] como clase contenida y contiene toda la funcionalidad de un Command. Puedes ver la clase en C# en la siguiente dirección. https://gist.github.com/schuster-rainer/2648922

A continuación puedes ver la adaptación que he hecho de esa clase para Visual Basic. Y observaras que el nombre que le he dado es el de [DelegateCommand], porque he visto que es el nombre que le dan los programadores (en general) a esa clase con objeto de distinguirla de otros modelos que toman el nombre se [RelayCommand].

Esta clase encapsula toda la operatoria de la interfaz [ICommand] y se usa por la [VistaModelo] y por la [Vista]

 

 

'/**

'--------------------------------------------------

' Version .....: 2015/01/28

'               [aaaa/mm/dd]

' Original en .: 

'--------------------------------------------------

'

' Clase .....: CommandBase

'

' Lenguaje ..: Visual Basic .NET (2012)

' Autor .....: Joaquin (jms32) Medina Serrano; en {AGUILA-joaquin}

' -------------------------------------------------

'*/

'

'----------------------------------------------------------

Option Explicit On

Option Strict On

Option Infer Off

Option Compare Binary

'------------------------------------------------------------

'

 

Imports System.Windows.Input ' para [ICommand]

 

 

''' <summary>

'''  Define un comando.

''' </summary>

''' <remarks>

''' <example>

''' <code>How to implement a reusable ICommand</code>

''' <code>http://www.wpftutorial.net/DelegateCommand.html</code>

'''

''' Compartiendo Código: Móvil + Web + Escritorio (2/2)

''' <code>http://geeks.ms/blogs/jyeray/archive/2010/11/14/compartiendo-c-243-digo-m-243-vil-web-escritorio-2-2.aspx</code>

''' </example>

'''

''' <example>

    ''' <code language="vb" title="Forma de usar la función NEW">

    ''' <![CDATA[

    '''

    '''   ' Instancia de la clase que implementa [Icommand]

    '''   Private _saveCommand As DelegateCommand

    '''

    '''    <summary>

    '''       Devuelve un [Comando] que guarda un cliente en el repositorio

    '''    </summary>

    '''    Public ReadOnly Property SaveCommand() As ICommand

    '''       Get

    '''           If _saveCommand Is Nothing Then

    '''               '-------------------------------

    '''               ' Los delegados de [Commnad]

    '''               ' El [Delegado] (la Accion) que llamara al metodo [Save]

    '''               Dim saveAction As Action(Of Object) = New Action(Of Object)(AddressOf Me.Save)

    '''               ' El [Delegado] que llamara al metodo [CanSave]

    '''               Dim canExecuteAction As Predicate(Of Object) = Function(param) Me.CanSave

    '''               '-------------------------------

    '''               ' Instanciar el Command ---> NEW <----

    '''               _saveCommand = New DelegateCommand(saveAction, canExecuteAction)

    '''               '

    '''           End If

    '''           Return _saveCommand

    '''       End Get

    '''    End Property

    '''

    '''

    '''    Public Sub Save(ByVal parameters As Object)

    '''      ' Proceso omitido para simplificar el codigo

    '''    End Sub

    '''

    '''    Private ReadOnly Property CanSave() As Boolean

    '''      Get

    '''          ' Proceso de validacion del cliente omitido

    '''          Return True

    '''      End Get

    '''    End Property

    '''

    ''' ]]>

    ''' </code>

''' </example>

''' </remarks>

Public Class DelegateCommand

    Implements ICommand, IDisposable

 

 

 

    ''' <summary>

    '''     Encapsula un método que no tiene parámetros y no devuelve un valor

    '''     Es el método que se tiene que ejecutar [Execute]

    ''' </summary>

    Protected _canExecuteAction As Predicate(Of Object) = Nothing

 

    ''' <summary>

    '''     Encapsula un método que  devuelve un valor Lógico

    '''     Es el método que devuelve el valor [CanExecute]

    ''' </summary>

    Protected _executeAction As Action(Of Object) = Nothing

 

    ''' <summary>

    '''  El nombre del comando (si se declara)

    '''  Solo a efectos informativos

    ''' </summary>

    Protected _nombreCommand As String

 

 

    ''' <summary>

    '''  El nombre del comando (si se declara)

    '''  Solo a efectos informativos

    ''' </summary>

    Public ReadOnly Property Name As String

        Get

            Return _nombreCommand

        End Get

    End Property

 

 

    Public ReadOnly Property GetCommand As ICommand

        Get

            Return Me

        End Get

    End Property

 

 

 

#Region "Constructores"

 

    ''' <summary>

    '''  Constructor para las clases derivadas únicamente

    ''' </summary>

    Protected Sub New()

        'Me.New(String.Empty, Nothing, Nothing)

    End Sub

 

 

    ''' <summary>

    '''  Constructor

    ''' </summary>

    ''' <param name="pexecute">

    '''  <para> <see cref="Action(Of Object)">Action(Of Object)</see></para>

    '''  <para> Encapsula un método que no tiene parámetros y no devuelve un valor</para>

    '''  <para> Es el método que se tiene que ejecutar [Execute]</para>

    ''' </param>

    Public Sub New(ByVal pexecute As Action(Of Object))

        Me.New(String.Empty, pexecute, Nothing)

    End Sub

 

 

    ''' <summary>

    '''  Constructor

    ''' </summary>

    ''' <param name="pname">

    '''  <para> <see cref="String">String</see></para>

    '''  <para> El nombre del comando. A efectos informativos únicamente</para>

    ''' </param>

    ''' <param name="pexecute">

    '''  <para> <see cref="Action(Of Object)">Action(Of Object)</see></para>

    '''  <para> Encapsula un método que no tiene parámetros y no devuelve un valor</para>

    '''  <para> Es el método que se tiene que ejecutar [Execute]</para>

    ''' </param>

    Public Sub New(ByVal pname As String, ByVal pexecute As Action(Of Object))

        Me.New(pname, pexecute, Nothing)

    End Sub

 

    ''' <summary>

    '''  Constructor

    ''' </summary>

    ''' <param name="pexecute">

    '''  <para> <see cref="Action(Of Object)">Action(Of Object)</see></para>

    '''  <para> Encapsula un método que no tiene parámetros y no devuelve un valor</para>

    '''  <para> Es el método que se tiene que ejecutar [Execute]</para>

    ''' </param>

    ''' <param name="pcanExecute">

    '''  <para> <see cref="Predicate(Of Object)">Predicate(Of Object)</see></para>

    '''  <para> Encapsula un método que  devuelve un valor Lógico</para>

    '''  <para> Es el método que devuelve el valor [CanExecute]</para>

    ''' </param>

    Public Sub New(ByVal pexecute As Action(Of Object), ByVal pcanExecute As Predicate(Of Object))

        Me.New(String.Empty, pexecute, pcanExecute)

    End Sub

 

    ''' <summary>

    '''  Constructor

    ''' </summary>

    ''' <param name="pname">

    '''  <para> <see cref="String">String</see></para>

    '''  <para> El nombre del comando. A efectos informativos únicamente</para>

    ''' </param>

    ''' <param name="pexecute">

    '''  <para> <see cref="Action(Of Object)">Action(Of Object)</see></para>

    '''  <para> Encapsula un método que no tiene parámetros y no devuelve un valor</para>

    '''  <para> Es el método que se tiene que ejecutar [Execute]</para>

    ''' </param>

    ''' <param name="pcanExecute">

    '''  <para> <see cref="Predicate(Of Object)">Predicate(Of Object)</see></para>

    '''  <para> Encapsula un método que  devuelve un valor Lógico</para>

    '''  <para> Es el método que devuelve el valor [CanExecute]</para>

    ''' </param>

    ''' <remarks>

    ''' <example>

    '''  <para>Forma de usar la función NEW y parámetros que espera recibir </para>

    '''

    ''' <code language="vb" title="Forma de usar la fucnion NEW">

    ''' <![CDATA[

    '''

    '''   ' Instancia de la clase que implementa [Icommand]

    '''   Private _saveCommand As DelegateCommand

    '''

    '''    <summary>

    '''       Devuelve un [Comando] que guarda un cliente en el repositorio

    '''    </summary>

    '''    Public ReadOnly Property SaveCommand() As ICommand

    '''       Get

    '''           If _saveCommand Is Nothing Then

    '''               '-------------------------------

    '''               ' Los delegados de [Commnad]

    '''               ' El [Delegado] (la Accion) que llamara al metodo [Save]

    '''               Dim saveAction As Action(Of Object) = New Action(Of Object)(AddressOf Me.Save)

    '''               ' El [Delegado] que llamara al metodo [CanSave]

    '''               Dim canExecuteAction As Predicate(Of Object) = Function(param) Me.CanSave

    '''               '-------------------------------

    '''               ' Instanciar el Command ---> NEW <----

    '''               _saveCommand = New DelegateCommand(saveAction, canExecuteAction)

    '''               '

    '''           End If

    '''           Return _saveCommand

    '''       End Get

    '''    End Property

    '''

    '''

    '''    Public Sub Save(ByVal parameters As Object)

    '''      ' Proceso omitido para simplificar el codigo

    '''    End Sub

    '''

    '''    Private ReadOnly Property CanSave() As Boolean

    '''      Get

    '''          ' Proceso de validacion del cliente omitido

    '''          Return True

    '''      End Get

    '''    End Property

    '''

    ''' ]]>

    ''' </code>

    ''' </example>

    ''' </remarks>

    Public Sub New(ByVal pname As String, ByVal pexecute As Action(Of Object), ByVal pcanExecute As Predicate(Of Object))

        MyBase.New()

        Call CreateCommand(pname, pexecute, pcanExecute)

        'Me._nombreCommand = pname

        'Me._execute = pexecute

        'Me._canExecute = pcanExecute

    End Sub

 

    ''' <summary>

    '''   Carga los valores del Command.

    '''   Se usa por las clases derivadas

    ''' </summary>

    ''' <param name="pname">

    '''  <para> <see cref="String">String</see></para>

    '''  <para> El nombre del comando. A efectos informativos unicamente</para>

    ''' </param>

    ''' <param name="pexecute">

    '''  <para> <see cref="Action(Of Object)">Action(Of Object)</see></para>

    '''  <para> Encapsula un método que no tiene parámetros y no devuelve un valor</para>

    '''  <para> Es el método que se tiene que ejecutar [Execute]</para>

    ''' </param>

    ''' <param name="pcanExecute">

    '''  <para> <see cref="Predicate(Of Object)">Predicate(Of Object)</see></para>

    '''  <para> Encapsula un método que  devuelve un valor Lógico</para>

    '''  <para> Es el método que devuelve el valor [CanExecute]</para>

    ''' </param>

    ''' <remarks>

    ''' </remarks>

    Protected Sub CreateCommand(ByVal pname As String, ByVal pexecute As Action(Of Object), ByVal pcanExecute As Predicate(Of Object))

        Me._nombreCommand = pname

        Me._executeAction = pexecute

        Me._canExecuteAction = pcanExecute

    End Sub

 

 

#End Region

 

 

    Private canExecuteValorAnterior As Boolean = False

 

 

    ''' <summary>

    '''   Define el método que determina si el comando se puede ejecutar en su estado actual.

    ''' </summary>

    ''' <param name="parameter">

    '''    <para>Tipo: <see cref="System.Object">System.Object</see> </para>

    '''    <para>Datos utilizados por el comando.</para>

    '''    <para>Si el comando no requiere datos para pasar, este objeto se puede

    '''       establecer en referencia null (Nothing en Visual Basic).</para>

    ''' </param>

    ''' <returns>

    '''     <para>Tipo: <see cref="System.Boolean">System.Boolean</see></para>

    '''     <para>true  si este comando se puede ejecutar; si no, false.</para>

    ''' </returns>

    ''' <remarks>

    '''     <para>

    '''         Normalmente, un origen de comando llama al método de

    '''         CanExecute cuando se provoca el evento de CanExecuteChanged.

    '''     </para>

    ''' </remarks>

    Public Function CanExecute(ByVal parameter As Object) As Boolean Implements System.Windows.Input.ICommand.CanExecute

 

        Dim resultado As Boolean = False

 

        If (_canExecuteAction Is Nothing) Then

            resultado = True

        Else

            resultado = _canExecuteAction(parameter)

            resultado = _canExecuteAction.Invoke(parameter)

        End If

 

        If canExecuteValorAnterior <> resultado Then

            canExecuteValorAnterior = resultado

            Call OnCanExecuteChanged()

        End If

 

        Return resultado

 

    End Function

 

 

    ''' <summary>

    ''' Define el método que se llamará cuando se invoca el comando.

    ''' </summary>

    ''' <param name="parameter">

    '''    <para>Tipo: <see cref="System.Object">System.Object</see> </para>

    '''    <para>Datos utilizados por el comando.</para>

    '''    <para>Si el comando no requiere datos para pasar, este objeto se puede

    '''       establecer en referencia null (Nothing en Visual Basic).</para>

    ''' </param>

    ''' <remarks></remarks>

    Public Sub Execute(ByVal parameter As Object) Implements System.Windows.Input.ICommand.Execute

        If _executeAction IsNot Nothing Then

            _executeAction(parameter)

        End If

    End Sub

 

 

    ''' <summary>

    '''    Se dispara cuando se producen cambios que afectan a si el comando se debe ejecutar.

    ''' </summary>

    ''' <remarks>

    '''  <para>

    '''     Normalmente, si no se puede ejecutar el comando, el origen de comando se deshabilita.</para>

    '''</remarks>

    Public Custom Event CanExecuteChanged As EventHandler Implements ICommand.CanExecuteChanged

        'Obligatorio.  Los eventos declarados como Custom deben definir descriptores

        'de acceso AddHandler, RemoveHandler y RaiseEvent personalizados.

        AddHandler(ByVal value As EventHandler)

            AddHandler CommandManager.RequerySuggested, value

        End AddHandler

        RemoveHandler(ByVal value As EventHandler)

            RemoveHandler CommandManager.RequerySuggested, value

        End RemoveHandler

        RaiseEvent(ByVal sender As System.Object, ByVal e As System.EventArgs)

        End RaiseEvent

    End Event

 

 

    ''' <summary>

    '''   Dispara el evento [CanExecuteChanged]

    ''' </summary>

    Public Sub OnCanExecuteChanged()

        RaiseEvent CanExecuteChanged(Me, EventArgs.Empty)

    End Sub

 

 

#Region "IDisposable Support"

    Private _disposedValue As Boolean ' Para detectar llamadas redundantes

 

    Protected Sub Dispose(disposing As Boolean)

        If Not Me._disposedValue Then

            If disposing Then

                If Not (Me._executeAction Is Nothing) Then

                    Me._executeAction = Nothing

                End If

                If Not (Me._canExecuteAction Is Nothing) Then

                    Me._canExecuteAction = Nothing

                End If

            End If

            Me._nombreCommand = Nothing

        End If

        Me._disposedValue = True

    End Sub

 

 

    Public Sub Dispose() Implements IDisposable.Dispose

        Dispose(True)

        GC.SuppressFinalize(Me)

    End Sub

#End Region

 

End Class

 

 

1.4.2       Ejemplo Un Command sin parámetros

 

Primero

Escribir el Command específico, por ejemplo un Command que muestre un mensaje al pulsar un botón

 

 

Public Class CommandHola

    Inherits DelegateCommand

    Implements IDisposable

 

    Public Sub New()

        MyBase.New()

 

        '-------------------------------

        ' Los parámetros de [Commnad]

        '-------------------------------

        ' El [Delegado] (la Accion) que llamara al método [Execute]

        Dim localExcuteAction As Action(Of Object) = New Action(Of Object)(AddressOf Me.Execute)

        ' El [Delegado] que llamara al método [CanExecute]

        Dim localCanExecuteAction As Predicate(Of Object) = Function(param) Me.CanExecute(param)

        ' El nombre de este command (A efectos informativos)

        'Dim localNombreCommand As String = "Hola Command"

        ' Solo el nombre de la clase

        Dim localNombreCommand As String = System.Reflection.MethodBase.GetCurrentMethod.DeclaringType.Name

 

        '-------------------------------

        ' Pasar los valores a la clase base

        '-------------------------------

        MyBase._nombreCommand = localNombreCommand

        MyBase._executeAction = localExcuteAction

        MyBase._canExecuteAction = localCanExecuteAction

 

    End Sub

 

 

 

    Public Overloads Sub Execute(parameter As Object)

        MessageBox.Show("Hola amigo !!! (Con invocación del comando)")

    End Sub

 

    Public Overloads Function CanExecute(parameter As Object) As Boolean

        Return True

    End Function

 

 

#Region "IDisposable Support"

    Private _disposedValue As Boolean ' Para detectar llamadas redundantes

 

    ' IDisposable

    Protected Overloads Sub Dispose(disposing As Boolean)

        If Not Me._disposedValue Then

            If disposing Then

                MyBase.Dispose()

            End If

        End If

        Me._disposedValue = True

    End Sub

#End Region

 

End Class

 

Segundo

Declarar este Command en el apartado [Window.Resources]

<Window.Resources>

        <local:CommandHola x:Key="CommandHolaResources" />

</Window.Resources>

Tercero

Enganchar el Command al botón

 

            <Button x:Name="ButtonHola" Content="Hola"

                HorizontalAlignment="Left" Margin="5"

                VerticalAlignment="Top" Width="75"

                Command="{Binding Mode=OneWay,

                                  Source={StaticResource CommandHolaResources}}"/>

 

1.4.3       Ejemplo (1) Un Command Con parámetros

 

En el parámetro de un Commad se puede pasar cualquier cosa, en este caso vamos a pasar el objeto [TiempoModeloVista] que lo tenemos enlazado a los controles con un Binding

Primero

Escribir el command , que lo que hará es colocar en los cuadros de texto hora, minutos y segundos la hora actual, tomada del sistema. Observa que el Command trabaja con las propiedades del objeto [TiempoModeloVista] y son estas propiedades las que actualiza, pero como están enlazadas [Binding] con cuadros TextBox, pues los cambios en sus valores se muestran también en la ventana principal

 

 

Public Class CommandAhora

    Inherits DelegateCommand

    Implements IDisposable

 

 

    Public Sub New()

        MyBase.New()

 

        '-------------------------------

        ' Los parámetros de [Commnad]

        '-------------------------------

        ' El [Delegado] (la Accion) que llamara al método [Execute]

        Dim localExcuteAction As Action(Of Object) = New Action(Of Object)(AddressOf Me.Execute)

        ' El [Delegado] que llamara al método [CanExecute]

        Dim localCanExecuteAction As Predicate(Of Object) = Function(param) Me.CanExecute(param)

        ' El nombre de este command (A efectos informativos)

        'Dim localNombreCommand As String = "Delete TextBox"

        ' solo el nombre de la clase

        Dim localNombreCommand As String = System.Reflection.MethodBase.GetCurrentMethod.DeclaringType.Name

 

        '-------------------------------

        ' Pasar los valores a la clase base

        '-------------------------------

        MyBase._nombreCommand = localNombreCommand

        MyBase._executeAction = localExcuteAction

        MyBase._canExecuteAction = localCanExecuteAction

 

    End Sub

 

 

 

    Public Overloads Sub Execute(parameter As Object)

        ' Recuperar el objeto pasado por parámetro

        Dim objTiempo As TiempoModeloVista

        objTiempo = TryCast(parameter, TiempoModeloVista)

 

        Dim ahora As DateTime = DateTime.Now

        objTiempo.Horas = ahora.Hour

        objTiempo.Minutos = ahora.Minute

        objTiempo.Segundos = ahora.Second

    End Sub

 

    Public Overloads Function CanExecute(parameter As Object) As Boolean

        Return True

    End Function

 

 

#Region "IDisposable Support"

    Private _disposedValue As Boolean ' Para detectar llamadas redundantes

 

    ' IDisposable

    Protected Overloads Sub Dispose(disposing As Boolean)

        If Not Me._disposedValue Then

            If disposing Then

                MyBase.Dispose()

            End If

        End If

        Me._disposedValue = True

    End Sub

#End Region

 

End Class

 

Segundo

Declarar este Command en el apartado [Window.Resources]

 

    <Window.Resources>

        <local:CommandAhora x:Key="CommandAhoraResources" />

    </Window.Resources>

 

Tercero

Enganchar el Command al botón

 <Button x:Name="ButtonAhora" Content="Ahora"

                HorizontalAlignment="Left" Margin="5"

                VerticalAlignment="Top" Width="75"

      Command="{Binding Mode=OneWay,

                        Source={StaticResource CommandAhoraResources}}"

      CommandParameter="{Binding Mode=OneWay,

                                 Source={StaticResource TiempoModeloVistaResources}}"

      CommandTarget="{Binding Mode=OneWay,

                              Source={StaticResource TiempoModeloVistaResources}}"/>

 

 

 

1.4.4       Ejemplo (2) Un Command Con parámetros

 

Ejemplo, queremos escribir un Command que borre un cuadro de texto. Evidentemente, el command estará enlazado con (por ejemplo) un botón y cuando se pulse se borrara el cuadro de texto. En este caso el valor que se recibe por parámetro en un control [TextBox]

Primero el Command

 

 

''' <summary>

'''   Borra el contenido de un TextBox

''' </summary>

Public NotInheritable Class TextBoxDeleteCommand

    Inherits DelegateCommand

    Implements IDisposable

 

 

    Public Sub New()

        MyBase.New()

 

        '-------------------------------

        ' Los parámetros de [Commnad]

        ' El [Delegado] (la Accion) que llamara al metodo [cmdExecute]

        Dim localExcuteAction As Action(Of Object) = New Action(Of Object)(AddressOf Me.cmdExecute)

        ' El [Delegado] que llamara al metodo [cmdCanExecute]

        Dim localCanExecuteAction As Predicate(Of Object) = Function(param) Me.cmdCanExecute(param)

        ' el nombre de este command

        Dim localNombreCommand As String = "Delete TextBox"

 

        '-------------------------------

        MyBase._nombreCommand = localNombreCommand

        MyBase._execute = localExcuteAction

        MyBase._canExecute = localCanExecuteAction

 

    End Sub

 

 

 

    ''' <summary>

    '''    Esta función Borra todo el texto de un textBox pasado por parámetro

    ''' </summary>

    Private Sub cmdExecute(ByVal parameter As Object)

        If parameter IsNot Nothing Then

            Dim target As TextBox = TryCast(parameter, TextBox)

            If target IsNot Nothing Then

                If target.Text.Length > 0 Then

                    target.Clear()

                End If

            End If

        End If

    End Sub

 

    ''' <summary>

    '''    Esta función Comprueba que en  TextBox haya un texto para poder ejecutar la función [Execute]

    '''    Si hay un texto devuelve (True) [Si se puede ejecutar], si no hay texto devuelve false [No se puede ejecutar]

    ''' </summary>

    Private ReadOnly Property cmdCanExecute(ByVal parameter As Object) As Boolean

        Get

            Dim resultado As Boolean = False

            If parameter IsNot Nothing Then

                Dim target As TextBox = TryCast(parameter, TextBox)

                If target IsNot Nothing Then

                    If target.Text.Length > 0 Then

                        resultado = True

                    End If

                End If

            End If

            Return resultado

        End Get

    End Property

 

 

 

#Region "IDisposable Support"

    Private _disposedValue As Boolean ' Para detectar llamadas redundantes

 

    ' IDisposable

    Protected Overloads Sub Dispose(disposing As Boolean)

        If Not Me._disposedValue Then

            If disposing Then

                MyBase.Dispose()

            End If

            '  liberar recursos no administrados (objetos no administrados) e invalidar Finalize() below.

            '  Establecer campos grandes como Null.

        End If

        Me._disposedValue = True

    End Sub

#End Region

 

End Class

 

Segundo, Declararlo en Window Resources de la Vista

 

    <UserControl.Resources>

        <!--el comando [Borrar un TetxBox]-->

        <local:TextBoxDeleteCommand x:Key="TextBoxDeleteCommandResources" />

    </UserControl.Resources>

 

 

Tercero el Botón

El TextBox que vamos a borrar

     <TextBox Grid.Column="0" x:Name="TextBoxInterno" />

 

 <Button x:Name="ButtonBorrarUri"

         Grid.Column="1"

         HorizontalAlignment="Right"  VerticalAlignment="Top" Width="20"

         Command="{Binding Mode=OneWay,

                    Source={StaticResource TextBoxDeleteCommandResources}}"

         CommandParameter="{Binding ElementName=TextBoxInterno,

                                    Mode=OneWay}"

         CommandTarget="{Binding ElementName=TextBoxInterno, Mode=OneWay}">

     <Button.Content>

         <Image Source="action_Cancel_16xLG_BN.png"

            Stretch="None" />

     </Button.Content>

 </Button>

 

 

2         WPF – Comandos Predefinidos

 

La implementación de WPF de ICommand es la clase RoutedCommand. Los principales orígenes de entrada en WPF son el mouse, el teclado, la entrada de lápiz y los comandos enrutados. Las entradas más orientadas a dispositivo utilizan un objeto RoutedEvent para notificar a los objetos de una página de aplicación que se ha producido un evento de entrada. Un RoutedCommand no es diferente.

Los métodos Execute y CanExecute de un objeto RoutedCommand no contienen la lógica de aplicación para el comando, sino que provocan eventos enrutados que se tunelizan y se propagar a través del elemento hasta que encuentran un objeto con CommandBinding.

El objeto CommandBinding contiene los controladores para estos eventos y son los controladores los que realizan el comando. Para obtener más información sobre el enrutamiento de eventos en WPF, vea MSDN - Información general sobre eventos enrutados.

El método Execute de un objeto RoutedCommand provoca los eventos PreviewExecuted y Executed en el destino del comando. El método CanExecute de un objeto RoutedCommand provoca los eventos CanExecute y PreviewCanExecute en el destino del comando. Estos eventos se tunelizan y se propagan a través del árbol de elementos hasta que encuentran un objeto que tiene un objeto CommandBinding para ese comando en particular.

 

2.1       Comandos por defecto

WPF proporciona un conjunto de comandos enrutados comunes y expuestos como propiedades estáticas en cinco clases diferentes: MediaCommands, ApplicationCommands, NavigationCommands, ComponentCommands y EditingCommands. Estas clases constan solamente de los objetos RoutedCommand 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.

2.1.1       ApplicationCommands

Close, Copy, Cut, Delete, Find, Help, New, Open, Paste, Print, PrintPreview, Properties, Redo, Replace, Save, SaveAs, SelectAll, Stop, Undo, etc.

2.1.2       ComponentCommands

MoveDown, MoveLeft, MoveRight, MoveUp, ScrollByLine, ScrollPageDown, ScrollPageLeft, ScrollPageRight, ScrollPageUp, SelectToEnd, SelectToHome, SelectToPageDown, SelectToPageUp, etc.

2.1.3       MediaCommands

ChannelDown, ChannelUp, DecreaseVolume, FastForward, IncreaseVolume, MuteVolume, NextTrack, Pause, Play, PreviousTrack, Record, Rewind, Select, Stop, etc.

2.1.4       NavigationCommands

BrowseBack, BrowseForward, BrowseHome, BrowseStop, Favorites, FirstPage, GoToPage, LastPage, NextPage, PreviousPage, Refresh, Search, Zoom, etc.

2.1.5       EditingCommands

AlignCenter, AlignJustify, AlignLeft, AlignRight, CorrectSpellingError, DecreaseFontSize, DecreaseIndentation, EnterLineBreak, EnterParagraphBreak, IgnoreSpellingError, IncreaseFontSize, IncreaseIndentation, MoveDownByLine, MoveDownByPage, MoveDownByParagraph, MoveLeftByCharacter, MoveLeftByWord, MoveRightByCharacter, MoveRightByWord, etc.

2.2       Uso de los Comandos desde XAML

Existen controles que incluyen y exponen la lógica de comandos por lo que no debemos de preocuparnos de realizar ningún trabajo sobre comandos. Estos controles implementan el interfaz ICommandSource exponiendo los siguientes miembros:

·         Command: Se le asigna el comando a ejecutar.

·         CommandParameter: Representa un valor definido por el usuario que será pasado como parámetro al comando.

·         CommandTarget: Objeto al que afecta la ejecución del comando.

 

En el siguiente ejemplo veremos cómo usar los comandos preestablecidos de Cortar, Pegar y Copiar que afectarán a una caja de texto. Estos comandos serán lanzados por varios botones de la barra de herramientas.

Utilizando DataBinding asignamos como CommandTarget el elemento de tipo TextBox y de nombre txtDocument. En Command irá cada uno de los comandos a asignar: Cut, Copy o Paste.

<StackPanel>

    <ToolBar>

      <Button Command="Cut"

              CommandTarget="{Binding  ElementName=txtDocument}">Cortar</Button>

      <Button Command="Copy"

              CommandTarget="{Binding ElementName=txtDocument}">Copiar</Button>

      <Button Command="Paste"

              CommandTarget="{Binding ElementName=txtDocument}">Pegar</Button>

   </ToolBar>

   <TextBox Name="txtDocument" Width="300"></TextBox>

</StackPanel>

 

image


 

2.3       Referencia Bibliográfica

 

·         CommandBinding (Clase)

·         http://msdn.microsoft.com/es-es/library/vstudio/system.windows.input.commandbinding.aspx

 

·         RoutedCommand (Clase)

·         http://msdn.microsoft.com/es-es/library/vstudio/system.windows.input.routedcommand.aspx

 

·         Wpf - La interfaz [INotifyPropertyChanged] http://joaquin.medina.name/web2008/documentos/informatica/lenguajes/puntoNET/System/Windows/WpfDocs/Docs/WPF_ImplementacionINotifyPropertyChanged.html

 

 

·         How to implement a reusable ICommand

·         http://www.wpftutorial.net/DelegateCommand.html

 

·         Compartiendo Código: Móvil + Web + Escritorio (2/2)

·         http://geeks.ms/blogs/jyeray/archive/2010/11/14/compartiendo-c-243-digo-m-243-vil-web-escritorio-2-2.aspx

 

·         Blog de Oskar Alvarez Commands en WPF

·         http://geeks.ms/blogs/oalvarez/archive/2009/07/10/commands-en-wpf.aspx

 

·         Implementation from Josh Smith of the RelayCommand

·         https://gist.github.com/schuster-rainer/2648922

 

·         A Practical Quick-start Tutorial on MVVM in WPF

·         http://www.codeproject.com/Articles/81484/A-Practical-Quick-start-Tutorial-on-MVVM-in-WPF

 

·         DelegateCommand in VB.NET

·         http://deepxpress.blogspot.com.es/2011/04/delegatecommand-in-vbnet.html

 

·         Descripción de eventos y comandos dirigidos en WPF

·         http://msdn.microsoft.com/es-es/magazine/cc785480.aspx