martes, 20 de marzo de 2012

Impedir Cortar / Pegar en un ComboBox

Los controles ComboBox no disponen de una propiedad ReadOnly, únicamente podemos ‘jugar’ con la propiedad Enabled.

Sin embargo, en ocasiones no es suficiente con la propiedad Enabled, sino que necesitamos, por ejemplo, que se pueda seleccionar el texto del control. Para conseguir esto es relativamente sencillo generar una propiedad ReadOnly que lo que haga sea modificar el estilo del ComboBox a “ComboBoxStyle.Simple”. Peeero, no es esa parte la que nos interesa, sino que lo que vamos a explicar es cómo impedir que se pueda utilizar el ratón para ‘Cortar’ y/o ‘Pegar’ el contenido del control.

Al turrón

Lo primero que hacemos es generar una clase que herede de “NativeWindow”, en la que sobrescribiremos el método “WndProc” que se invoca cada vez que se lanza un mensaje al handle de la ventana.

El código de la clase aparece a continuación.

 

    /// <summary>
    /// Esta clase se utiliza para evitar las operaciones de Cortar / Pegar en los combos deshabilitados.
    /// </summary>
    public class DisallowCutPaste : NativeWindow
    {
        #region
Constantes
        private const int WM_CUT = 0x0300;
       
private const int WM_PASTE
= 0x0302;

        #endregion
Constantes

        #region
Overrides
        
/// <summary>
        /// Sobrecarga del método <see cref="WndProc"/> para evitar operaciones de cortar / pegar.
        /// </summary>
        /// <param name="m">
        /// El <see cref="Message"/> recibido por el objeto.
        /// </param>
        protected override void WndProc(ref Message m
)
        {
           
if (m.Msg == WM_CUT || m.Msg == WM_PASTE
)
            {
               
return
;
            }

           
base.WndProc(ref m
);
        }

        #endregion

    }

Una vez generada la clase, la aplicamos al control que queremos manipular (en este caso un ComboBox personalizado)


Para esto, en el código del control referenciamos la siguiente función del API:


 

        [DllImport("user32.dll", SetLastError = true)]
       
private static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter
,
           
string lpszClass, string lpszWindow
);

Ya sólo queda aplicar todos los elementos para que todo funcione, como podemos ver en este fragmento de código:


 

    IntPtr handle = FindWindowEx(this.Handle, IntPtr.Zero, "EDIT", null);
   
DisallowCutPaste p = new DisallowCutPaste
();
   
p.AssignHandle(handle
);

Una vez hecho esto, ya podremos comprobar que aunque en el combo tengamos disponible las opciones de ‘Cortar’ y ‘Pegar’ con el botón derecho del ratón, cuando el código anterior se ejecuta, al utilizar esas opciones, no sucede… NADA.


Nota


Hay que decir que estas instrucciones es recomendable ejecutarlas solamente cuándo sea necesario, por ejemplo en el “Set” de una propiedad, de forma que para desactivarlo sólo hace falta no ejecutar el código en el mismo “Set” de la propiedad (por ejemplo en un bloque ‘If’) el siguiente fragmento de código explica un poco mejor esta observación:

        public bool ReadOnly
        {
           
get
            {
               
return this._readOnly
;
            }
           
set
            {
               
if (value
)
                {
                   
IntPtr handle = FindWindowEx(this.Handle, IntPtr.Zero, "EDIT", null
);
                   
DisallowCutPaste p = new DisallowCutPaste
();
                   
p.AssignHandle(handle
);
                }
               
this._readOnly = value
;
            }
        }

Y esto es todo.

No hay comentarios: