Ir al contenido principal

¿Como crear un control personalizado en .Net C#/VBasic?

Descargar Codigo Fuente 93.99KB

Descargar Projecto de Muestra 56.13KB

En muchas ocasiones nos hemos visto en la necesidad de crear, extender o personalizar alguno que otro de los controles nativos del .Net Framework ya sea en C# o Visual Basic, cuando es un control simple esto suele ser fácil ya que solemos agregar nuevas propiedades y ocultar las que no son necesarias o modificar el Paint para hacer que el control se pinte al gusto nuestro, claro!!!!… este ultimo a según el control.

Pero cuando es un control que contendrá otros controles personalizados el tema cambia, ya que hay que crear el editor de la colección del control que contendrá nuestro control, interactuar con el diseñador del Visual Studio para hacer uso de los comandos Deshacer (Undo) y Rehacer (Redo) y modificar el Smart Tag del control Padre (Contenedor) para agregar métodos o propiedades que queremos sean de acceso rápido.

Para poder ver este tema he creado un nuevo control que he llamado GroupPanel, este hereda de System.Windows.Forms.Control y la idea de este es agrupar paneles y permite título en estos.

Ejemplo:

image

 

Clases e Interfaces

Las clases que usa este control son las siguientes:

ParentControlDesigner

TypeConverter

CollectionBase

CollectionEditor

DesignerActionList

DesignerActionUIService

Interfaces

INotifyPropertyChanged

IDesignerHost

IComponentChangeService

 

Puntos Importantes

Para agregar un nuevo panel se hace uso de la Interfaz IDesignerHost para crear el nuevo control y poder interactuar con este en tiempo de diseño.

 

Codigo para agregar nuevo panel desde el editor de la colección

   1: internal GroupPanelContainer CreateGroupPanelContainer()
   2: {
   3:     IDesignerHost host = null;
   4:     if (Site != null)
   5:         host = Site.GetService(typeof(IDesignerHost)) as IDesignerHost;
   6:  
   7:     GroupPanelContainer panelContainer = host.CreateComponent(typeof(GroupPanelContainer)) as GroupPanelContainer;
   8:     Controls.Add(panelContainer);
   9:     return panelContainer;
  10: }

Codigo para agregar nuevo panel usando el metodo “Add Panel” del Smart Tag
 
 


   1: internal void AddPanel()
   2: {
   3:     IDesignerHost host = Site.GetService(typeof(IDesignerHost)) as IDesignerHost;
   4:     IComponentChangeService componentChangeSvc = host.GetService(typeof(IComponentChangeService)) as IComponentChangeService;
   5:     DesignerTransaction t = host.CreateTransaction("Adding Component");
   6:     GroupPanelContainer panel = host.CreateComponent(typeof(GroupPanelContainer)) as GroupPanelContainer;
   7:     panel.Owner = this;
   8:     componentChangeSvc.OnComponentChanging(this, null);
   9:     Controls.Add(panel);
  10:     Panels.Add(panel);
  11:     componentChangeSvc.OnComponentChanged(this, null, null, null);
  12:     t.Commit();
  13: }

 


Al iniciarse el control instanciamos los eventos ComponentRemoving y ComponentRemoved de la interfaz IComponentChangeService para anunciar al servicio de cambio del component que nuestro control ha hecho cambios en la propiedad “Panel” al remover un panel.



   1: private void componentChangeSvc_ComponentRemoving(object sender, ComponentEventArgs e)
   2: {
   3:     if (designerHostSvc.InTransaction && designerHostSvc.TransactionDescription.Contains(e.Component.Site.Name))
   4:         return;
   5:  
   6:     if (e.Component is GroupPanelContainer)
   7:     {
   8:         componentChangeSvc.OnComponentChanging(Owner, TypeDescriptor.GetProperties(Owner)["Panels"]);
   9:         Owner.Panels.Remove(e.Component as GroupPanelContainer);
  10:     }
  11: }
  12: private void componentChangeSvc_ComponentRemoved(object sender, ComponentEventArgs e)
  13: {
  14:     if (designerHostSvc.InTransaction && designerHostSvc.TransactionDescription.Contains(e.Component.Site.Name))
  15:         return;
  16:  
  17:     if (e.Component is GroupPanelContainer)
  18:     {
  19:         componentChangeSvc.OnComponentChanged(Owner, TypeDescriptor.GetProperties(Owner)["Panels"], null, null);
  20:     }
  21: }

 


Ya que se está utilizando la clase ParentControlDesigner y no queremos que se agreguen controles arrastrando estos sobre nuestro control en tiempo de diseño, se ha establecido la propiedad “AllowDrop = false” y esta no está disponible para ser cambiada en el control, la otra forma de resolverlo hubiera sido usar ControlDesigner pero no es esta clase la que deseo utilizar para este control.


Resumen


La idea no era crear un artículo demasiado extenso, así que resumí este de la forma que creo más conveniente “creo yo” y lo mejor es ver en funcionamiento el control.


Espero les sea de mucha utilidad para aquellos que buscan crear o extender los controles de .Net Framework


Y no olviden dejar sus comentarios.


Salu2,

Comentarios

  1. Donde puedo conseguir mas documentacion al respecto

    ResponderEliminar
  2. Marvin. Este es un gran control.
    ¿Cuál es la licencia de uso?
    Gracias

    ResponderEliminar
  3. Copyleft: http://www.gnu.org/copyleft/copyleft.es.html

    Salu2,

    ResponderEliminar
  4. Hola Marvin, quisiera aprender mas sobre como diseñar controles, por ejemplo me da curiosidad saber como diseñaste el netBarControl. espero me puedas dar una ayuda, o me puedas orientar donde encontrarla.
    Atte: Oscar E. Alvarado

    ResponderEliminar
  5. Hola Marvin
    Quiero agregarle propiedades a un textBox si me puedes brindar información conde investigar para aprender hacerlo, te dejo un link donde hice la pregunta en el foro msdn http://social.msdn.microsoft.com/Forums/es-ES/vcses/thread/ec55e1cb-a585-495a-832c-4526c46285f0/

    ResponderEliminar
  6. Buen dia Marvin. Disculpa me podrias ayudar para que un groupbox se le pueda centrar en texto. En VB.

    ResponderEliminar

Publicar un comentario

Entradas populares de este blog

TextBox con Borde Personalizado

Bien, retomando nuevamente mi blog, luego de tanto tiempo ausente, veremos como personalizar el borde del control TextBox con un color diferente. hace poco vi en los foros de MSDN, en el foro de VB.Net esta pregunta, ¿ Cómo puedo cambiar el color del borde de un control TextBox ?, anteriormente también se hizo la misma pregunta en este mismo foro donde yo respondí como hacerlo VB2010 4.0 - Como crear un textbox personalizado . no hay manera fácil de personalizar un control, generalmente se tiene que sobre escribir el evento WndProc para escuchar los mensajes de window y reemplazar la funcionalidad de estos según sea la necesidad o el control. bien, para cambiar el color del borde del control TextBox sin mucha funcionalidad, se debe de escuchar y reemplazar el funcionamiento de los mensajes WM_PAINT y WM_NCPAINT . ¿ Porque WM_PAINT ?, porque cuando cambiamos la propiedad BorderStyle de este control a FixedSingle, quien pinta el borde es el mensaje WM_PAINT no asi el WM_NC

TextBox con Icon/Imagen

Bien, continuando con este articulo: TextBox con borde personalizado , ahora le dare la funcionalidad de poder mostrar un icono o imagen dentro del Control TextBox. Existen dos maneras de hacer esto: Pintar el icono/imagen dentro del control o Pintar el icono/imagen dentro del Non-Client Area del control. Pintar el icono/imagen dentro del control. Antes de escribir el código decidi googlear un poco, para ver si alguien más ya habia tenido la misma idea de usar el mensaje EM_SETMARGINS para dejar el espacio necesario para pintar el icono o imagen ya sea a la derecha o izquierda y me he encontrado con este articulo. Adding an Icon or Control to a TextBox or ComboBox . Pintar el icono/imagen de ntro del Non-Client Area del control. Us ando el Non- Client Area no encontre resultados googleando, así que es la forma que usar e para dib ujar un icono o imagen dentro de un control TextBox. En el control TextEditor que escrib í, utilizo esta manera para pintar el icono

Personalizar DataGridView (II) - Bloquear columnas de solo lectura

Personalizar DataGridView - Actualizaciones Personalizar DataGridView (II.1) - Bloquear columnas de solo lectura. Personalizar DataGridView (III) - Cambiar Diseñador. Bien, continuando con el articulo " Personalizar DataGridView (I) - Pintar área vacía ", ahora lo que haré es darle al control la funcionalidad de bloquear las columnas cuya propiedad " ReadOnly " se establezca en " true ", entiéndase por "Bloquear" el evitar que las columnas cuya propiedad " ReadOnly=true " puedan recibir el foco, ya sea por el teclado o por el ratón ( mouse ). Para tal objetivo agregare una nueva propiedad al control la cual llamare " AllowFocusReadOnlyColumns " cuyo valor predeterminado sera " true ", en caso de ser " false " las columnas marcadas como solo lectura no recibirán el foco. También le daré la funcionalidad de poder avanzar a la siguiente columna al presionar la tecla " ENTER " agregando otr