jueves, 22 de diciembre de 2011

Personalizar DataGridView (II.1) - Bloquear columnas de solo lectura

Bien, continuando con la personalización del control DataGridView y como ya hemos visto en los artículos anteriores.

Personalizar DataGridView (III) - Cambiar Diseñador.

Continuaremos con el articulo II, en ocasiones se nos presenta la necesidad de saltar "x" columna de este control sin necesidad de que esta este marcada como solo lectura, por el simple hecho de que el usuario no quiere pasar sobre esta columna porque no necesita modificar su contenido, salvo en aquellos casos que si se requiera, generalmente no se quiere atrasar pasando sobre estas columnas.

Para estos casos lo que yo he hecho es agregarle un evento al control al cual he llamado "BeforeFocusColumn" el cual se ejecuta antes de cambiar la columna activa, con la idea de validar la columna que recibirá el foco, validar y en caso de ser necesario cambiar esta columna por la que nosotros necesitemos que reciba el foco.

ejemplo:
 
private void view_BeforeFocusColumn(object sender, BeforeFocusColumnEventArgs e)
{
    if (e.NewColumnIndex == this.colDescripcion.Index)
    {
        if (e.OldColumnIndex == this.colPrecioVenta.Index)
        {
            e.NewColumnIndex = this.colCodigo.Index;
        }
        else
        {
            // descomente esta linea para provocar una excepción al intentar
            // asignar a CurrentCell una celda no visible.
            //e.NewColumnIndex = this.colMarca.Index;
            e.NewColumnIndex = this.colPrecioVenta.Index;
        }
    }
}
 
Como podemos ver en el código de ejemplo, el evento recibe dos parámetros:
object sender: que viene a ser el control que invoca el evento.
BeforeFocusColumnEventArgs e: un nuevo argumento de evento que he creado para pasar la información necesaria al evento.

[C#]
 
public class BeforeFocusColumnEventArgs : EventArgs
{
    private MEPDataGridView Owner = null;
    private int vNewColumnIndex = -1;
    public int OldColumnIndex { get; private set; }
    public int NewColumnIndex 
    {
        get { return vNewColumnIndex; }
        set
        {
            if (this.Owner != null && this.Owner.IsHandleCreated)
            {
                if (value < 0 || value > (this.Owner.Columns.Count - 1))
                    throw new Exception("Invalid current cell index");
                else if (!this.Owner.Columns[value].Visible)
                    throw new Exception("Current cell cannot be set to an invisible cell.");
                this.vNewColumnIndex = value;
            }
        }
    }

    public BeforeFocusColumnEventArgs(int currentColumnIndex, int focusColumnIndex, MEPDataGridView owner)
    {
        this.Owner = owner;
        this.OldColumnIndex = currentColumnIndex;
        this.NewColumnIndex = focusColumnIndex;
    }
}
 
como podemos observar en el constructor de la clase la cual hereda de "EventArgs",  también recibe como parámetro el control propietario, esto con la idea de; hay que validar la columna que el programador indique que recibirá el foco en sustitución de la columna que el control nos indica que recibirá el foco.

esta validación la puede haber hecho desde el evento que ejecuta el evento pero!!!!... al hacer la validación y provocar la excepción la linea donde se marcara la excepción sera dentro de la clase "Program" en el caso de [C#], en la linea "Application.Run(new Form1());" y aquí sera difícil saber donde se ocasiono la excepción; así que, para que se marque la linea que provoca la excepción es mejor provocar esta en la propiedad "NewColumnIndex" cuando su valor es cambiado.

Este nuevo evento "BeforeFocusColumn" se ejecuta o dispara desde del evento "SetCurrentCellAddressCore".

[C#]
 
protected override bool SetCurrentCellAddressCore(int columnIndex, int rowIndex, bool setAnchorCellAddress, bool validateCurrentCell, bool throughMouseClick)
{
    if (!throughMouseClick)
    {
        int currentCellIndex = -1;
        if (this.CurrentCell != null)
            currentCellIndex = this.CurrentCell.ColumnIndex;

        BeforeFocusColumnEventArgs ea = new BeforeFocusColumnEventArgs(currentCellIndex, columnIndex, this);
        this.OnBeforeFocusColumn(ea);
        if (ea.NewColumnIndex != columnIndex)
        {
            // unselect old column index
            this.SetSelectedCellCore(columnIndex, rowIndex, false);
            // select new column index
            this.SetSelectedCellCore(ea.NewColumnIndex, rowIndex, true);
            columnIndex = ea.NewColumnIndex;
        }
    }

    return base.SetCurrentCellAddressCore(columnIndex, rowIndex, setAnchorCellAddress, validateCurrentCell, throughMouseClick);
}
 
Ademas, como podemos ver en el código, nuestro nuevo evento es ejecutado solo si la celda es cambiada por el teclado, en caso de ser cambiada por el ratón (mouse) no se ejecutara permitiendo que la celda reciba el foco, ya que la idea es esta, que el usuario final pueda modificar el contenido de la celda, posicionándose en la celda usando el ratón (mouse) pero no el teclado.



Como siempre, espero les sea de utilidad y no olviden dejar sus comentarios.


Salu2,

miércoles, 21 de diciembre de 2011

Personalizar DataGridView - Actualizaciones


Revisión 12 Diciembre 2011.

  • Mejora en los métodos auxiliares para saltar las columnas marcadas como solo lectura, considerando las columnas marcadas como no visibles, como también si el control no es el primero en recibir el foco al mostrarse su formulario o contenedor.
  • Se cambio la forma de procesar la tecla "ENTER" para avanzar a la siguiente columna, sobre escribiendo el método ProcessCmdKey.
[C#]
 
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
    if (keyData == Keys.Enter && this.EnterMoveNextColumn)
    {
        msg.WParam = (IntPtr)NativeMethods.VK_TAB;
        return base.ProcessCmdKey(ref msg, Keys.Tab);
    }
    return base.ProcessCmdKey(ref msg, keyData);
}
 
Descargar:
Codigo Fuente [C#]

lunes, 12 de diciembre de 2011

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 otra propiedad que llamare "EnterMoveNextColumn" cuyo valor predeterminado sera "true"

[C#]
 
private bool vAllowFocusReadOnlyColumns;
private bool vEnterMoveNextColumn;

[DefaultValue(true)]
public bool AllowFocusReadOnlyColumns
{
    get { return vAllowFocusReadOnlyColumns; }
    set { vAllowFocusReadOnlyColumns = value; }
}

[DefaultValue(true)]
public bool EnterMoveNextColumn
{
    get { return vEnterMoveNextColumn; }
    set { vEnterMoveNextColumns = value; }
}
 
[VB.NET]
 
Private vAllowFocusReadOnlyColumns As Boolean
Private vEnterMoveNextColumn As Boolean

<DefaultValue(True)> _
Public Property AllowFocusReadOnlyColumns() As Boolean
    Get 
        Return vAllowFocusReadOnlyColumns
    End Get
    Set (ByVal value As Boolean)
        vAllowFocusReadOnlyColumns = value
    End Set
End Property

<DefaultValue(True)> _
Public Property EnterMoveNextColumn() As Boolean
    Get
        Return vEnterMoveNextColumn
    End Get
    Set (ByVal value As Boolean)
        vEnterMoveNextColumn = value
    End Set
End Property
 
Para agregarle esta funcionalidad al control sobre escribiré el método "WndProc" para escuchar el mensaje del teclado "WM_KEYDOWN" y los mensajes del ratón (mouse) "WM_LBUTTONDBLCLK", "WM_LBUTTONDOWN" y el mensaje "WM_SETFOCUS", en caso de no permitir que las columnas marcadas como solo lectura reciban el foco, estos mensajes no serán procesados por el método base del control. 

[C#]
 
[PermissionSet(SecurityAction.Demand, Name = "FullTrust")]
protected override void WndProc(ref Message m)
{
    switch (m.Msg)
    {
        case NativeMethods.WM_SETFOCUS:
            this.WmSetFocus(ref m);
            break;
        case NativeMethods.WM_LBUTTONDBLCLK:
            this.WmLButtonDblClk(ref m);
            return;
        case NativeMethods.WM_LBUTTONDOWN:
            this.WmLButtonDown(ref m);
            return;
        case NativeMethods.WM_KEYDOWN:
            this.WmKeyDown(ref m);
            return;
    }
    base.WndProc(ref m);
}
 
[VB.NET]
 
<PermissionSet(SecurityAction.Demand, Name:="FullTrust")> _
Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)
    Select Case m.Msg
        Case NativeMethods.WM_SETFOCUS
            Me.WmSetFocus(m)
        Case NativeMethods.WM_LBUTTONDBLCLK
            Me.WmLButtonDblClk(m)
            Return
        Case NativeMethods.WM_LBUTTONDOWN
            Me.WmLButtonDown(m)
            Return
        Case NativeMethods.WM_KEYDOWN
            Me.WmKeyDown(m)
            Return
    End Select

    MyBase.WndProc(m)
End Sub
 
Y a continuación los proyectos para que los descarguen.

Código fuente [C#]
Código fuente [VB.NET]

En el próximo articulo lo que haré sera agregar un evento al control para poder indicar si la columna puede recibir el foco sin necesidad de que la propiedad "ReadOnly" este establecida en "true", ya que el algunos casos no necesitamos que la celda reciba el foco pero si que pueda ser editada.

Espero sea de utilidad este articulo y no olviden dejar sus comentarios.

Salu2,

domingo, 11 de diciembre de 2011

Personalizar DataGridView (I) - Pintar área vacía

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, como lo dice el titulo vamos a personalizar el control DataGridView y lo haremos en varios artículos, en este lo que hare es pintar el área del control que queda vacía cuando tenemos un origen de datos con pocos registros, a esta área la llamare "Empty Area", así que en lugar de que se vea de esta manera.


haré que se vea de esta otra manera.


para esto crearemos nuestro propio control que herede de DataGridView al cual llamare MEPDataGridView, sobre escribiremos los métodos OnCellPainting y OnPaint del control, creare 5 métodos auxiliares "PaintColumnHeader", "PaintIndicatorHeader", "PaintRowIndicator", "PaintCell" y "PaintEmptyArea" y un Argumento "PaintingEventArgs" que hereda de EventArgs que sera pasado a algunos de los métodos auxiliares. 

[C#]
 
public class MEPDataGridView : DataGridView
{        
    
    public MEPDataGridView()        
    {            
        this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
        this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
        this.SetStyle(ControlStyles.ResizeRedraw, true);
        this.DoubleBuffered = true;        
    }

}
 
[VB.NET]
 
Public Class MEPDataGridView    
    Inherits DataGridView    
 
    Public Sub New()        
        Me.SetStyle(ControlStyles.AllPaintingInWmPaint, True)
        Me.SetStyle(ControlStyles.OptimizedDoubleBuffer, True)
        Me.SetStyle(ControlStyles.ResizeRedraw, True)
        Me.DoubleBuffered = True    
    End Sub

End Class
 

como bien podemos observar en el constructor he activado el DoubleBuffer para reducir el parpadeo (flicker) al dibujar el control cuando este cambie de dimensiones, para mayor referencia ControlStyles.

desde este articulo dibujare los encabezados de las columnas para mantener uniformidad en los colores de estas ya que al tener habilitados los estilos visuales para la aplicación "Application.EnableVisualStyles", es dificil obtener los colores predeterminados con que se pintan los encabezados, y en este caso necesito hacerlo así para mantener uniformidad al pintar la columna indicador en el "Empty Area".

Ahora agregaremos una nueva propiedad al control para indicarle cuando queremos que se pinten las filas en el "Empty Area", ha esta propiedad la llamare "FillEmptyArea" cuyo tipo sera "Boolean" true/false, cuyo valor predeterminado sera "false".

[C#]
 
private bool vFillEmptyArea;    

[DefaultValue(false)]
public bool FillEmptyArea
{
    get
    {
        return this.vFillEmptyArea;
    }
    set
    {
        this.vFillEmptyArea = value;
        if (this.IsHandleCreated)
            this.Invalidate(true);
    }
}
 
[VB.NET]
 
Private vFillEmptyArea As Boolean

<DefaultValue(False)> _
Public Property FillEmptyArea() As Boolean
    Get
        Return Me.vFillEmptyArea
    End Get
    Set(ByVal value As Boolean)
        Me.vFillEmptyArea = value
        If Me.IsHandleCreated Then
            Me.Invalidate(True)
        End If
    End Set
End Property
 

Ademas hare visible la propiedad “AutoGenerateColumns” para poder cambiar esta desde las propiedades del control en tiempo de diseño.

[C#]
 
[Browsable(true), DefaultValue(true)]
public new virtual bool AutoGenerateColumns
{
    get
    {
        return vAutoGenerateColumns;
    }
    set
    {
        vAutoGenerateColumns = value;
        base.AutoGenerateColumns = value;
    }
}
 
[VB.NET]
 
<Browsable(True), DefaultValue(True)> _
Public Overloads Property AutoGenerateColumns() As Boolean
    Get
        Return Me.vAutoGenerateColumns
    End Get
    Set(ByVal value As Boolean)
        Me.vAutoGenerateColumns = value
        MyBase.AutoGenerateColumns = value
    End Set
End Property
 

Ahora sobre escribiremos el evento "OnCellPainting" del control para dibujar los encabezados de las columnas y dibujar el indicador de la fila de cada registro del origen de datos.

[C#]
 
protected override void OnCellPainting(DataGridViewCellPaintingEventArgs e)
{
    base.OnCellPainting(e);
    if (e.RowIndex == -1 && e.ColumnIndex == -1)
    {
        // Método auxiliar para pintar el encabezado de la columna indicador.
        this.PaintIndicatorHeader(e);
    }
    else if (e.RowIndex == -1 && e.ColumnIndex > -1)
    {
        // Método auxiliar para pinta los encabezados de las columnas
        this.PaintColumnHeader(new PaintingEventArgs(e.Graphics, e.CellBounds, e.RowIndex, e.ColumnIndex));
        e.PaintContent(e.ClipBounds);
        e.Handled = true;
     }
     else if (e.ColumnIndex == -1)
     {
        // Método auxiliar para pinta la columna indicador.
        this.PaintRowIndicator(new PaintingEventArgs(e.Graphics, e.CellBounds, e.RowIndex, e.ColumnIndex));
        e.PaintContent(e.ClipBounds);
        e.Handled = true;
     }
}
 
[VB.NET]
 
Protected Overrides Sub OnCellPainting(ByVal e As DataGridViewCellPaintingEventArgs)
    MyBase.OnCellPainting(e)

    If e.RowIndex = -1 And e.ColumnIndex = -1 Then
        ' Método auxiliar para pintar el encabezado de la columna indicador.
        Me.PaintIndicatorHeader(e)
    ElseIf e.RowIndex = -1 And e.ColumnIndex > -1 Then
        ' Método auxiliar para pinta los encabezados de las columnas
        Me.PaintColumnHeader(New PaintingEventArgs(e.Graphics, e.CellBounds, e.RowIndex, e.ColumnIndex))
        e.PaintContent(e.ClipBounds)
        e.Handled = True
    ElseIf e.ColumnIndex = -1 Then
        ' Método auxiliar para pinta la columna indicador.
        Me.PaintRowIndicator(New PaintingEventArgs(e.Graphics, e.CellBounds, e.RowIndex, e.ColumnIndex))
        e.PaintContent(e.ClipBounds)
        e.Handled = True
    End If

End Sub
 
Luego sobre escribimos el evento "OnPaint" para dibujar las filas o lineas para llenar el "Empty Area"

[C#]
 
protected override void OnPaint(PaintEventArgs e)
{
    base.OnPaint(e);
    if (this.FillEmptyArea)
        // Método auxiliar para pintar el área vacía
        this.PaintEmptyArea(e);
}
 
[VB.NET]
 
Protected Overrides Sub OnPaint(ByVal e As PaintEventArgs)
    MyBase.OnPaint(e)
    If Me.FillEmptyArea Then _
        Me.PaintEmptyArea(e) ' Método auxiliar para pintar el área vacía
End Sub
 


y aquí les dejos los proyectos para que los descarguen.

Código fuente [C#]
Código fuente [VB.NET]


En el próximo artículo veremos como evitar que el usuario pueda colocarse sobre las columnas cuya propiedad "ReadOnly" este establecida en "true".


Espero que sea de utilidad este artículo y no olviden dejar sus comentarios.

Salu2,

jueves, 27 de octubre de 2011

How to: Adding "Control" inside "ComponentTray" in "VS" design surface

Bueno, ultima mente he estado visitando el foro de Windows Form Designer ya que es un foro donde se trata mucho sobre diseñar controles personalizados, he respondido a un par de preguntas pero la que más me llamo la atención es esta: 


Aún estoy pensando la utilidad que se le podría dar al agregar un control al área de componentes del diseñador, pero bien!!!... si Microsoft lo implementa con el control "ToolStrip", pues su uso tendrá, cada cabeza es un mundo así que me di a la tarea de buscar la forma de hacer lo que se pedía en esa pregunta, hasta que encontré dos maneras de hacerlo. ¿Donde las encontré?... en mi cabeza. naaaaaaa... bueno!!!, si, solo que tuve que debuggear mucho.

Brinde dos opciones para hacerlo, la segunda opción tiene un error, ya que se usa una interfaz que es interna, la cual esta en el namespace "System.Windows.Forms.Design.ISplitWindowService" por alguna razón Microsoft decidió no hacer publica esta interfaz aún que se puede tener acceso a ella en tiempo de diseño como se muestra en el ejemplo.

Bueno, el error tiene solución solo que hay que seguir investigando para resolver algo que tiene una solución más digamos "practica", la cual es la que se implementa en la primera opción.

Realmente se aprende mucho en estos foros, así que los invito a que pasen a revisar las preguntas que se suelen hacer por aquí, pueda que encuentres como hacer algo que pensaste que no se podía hacer.

Salu2,

domingo, 9 de octubre de 2011

¿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,

martes, 23 de agosto de 2011

Instalador

FreeDownload2
Bueno, en vista de la reciente demanda en algunos de mis controles he decidido crear un instalador para que estos controles (NetBarControl y TextEditor) se agreguen a la barra de herramientas del Visual Studio.
Instalador
Este instalador funciona para VS2008 y VS2010 y asumo que también funcionara para la próxima versión de VS.
En caso de que tenga las dos versiones de VS deberán seleccionar en que versión de VS desean que se agreguen los controles en la barra de herramientas.
Instalador1
y luego en la barra de herramientas del VS deberá de aparecer de la siguiente manera.
Instalador2

Al descargar el archivo lo pueden descomprimir en cualquier directorio de su disco duro ejemplo: “C:\OtrosControles” y ejecutan el archivo “Instalador.exe
Y si se pregunta ¿Como lo hizo?, bueno, pues les debo el Link al artículo porque no lo tengo guardado en los favoritos de esta computadora…
ah!!!!… lo olvidaba, en esta archivo comprimido ya va la ultima versión de ambos controles corrigiendo los problemas que ha reportado en NetBarControl al cambiar el ForeColor de los Items de cada grupo.

bueno, este es el Link al articulo donde esta un código de ejemplo para agregar tus controles personalizados al toolbox del VS.


Salu2,

viernes, 22 de julio de 2011

TextEditor

TextEditor
Este control nace a raíz de una pregunta en el foro de Visual Basic .Net, sobre como cambiar el borde de un TextBox a un borde personalizado y además andaba buscando cambiar la apariencia del control NetBarControl para poder aplicarle una nueva propiedad para cambiar el estilo.
ejemplo:
NetBarControlX

Aun que esta imagen solo es un pre-formato de cómo funcionara el control NetBarControl, solo que me distraje creando este nuevo control TextEditor. Así que le echaré mano al terminado este nuevo control.








Bien, la idea inicial era solo agregar botones a un control TextBox, pero luego usando el Mozilla, al descargar unos archivos me percate de un control en la parte inferior de esta venta de descargar, aun que se suele ver mucho en las páginas Web, pero me llamo la atención aquí en el Mozilla y en el Window Live Messenger.
clip_image005
clip_image007
Entonces… me entro el gusano de la curiosidad, agregar la imagen luego de agregar los botones ya no era la parte difícil, la parte curiosa es mostrar el Texto como marca de agua, encontré varios ejemplos en la Red (Internet) pero…. No llenaron mis expectativas ya que estos usan el Paint del Control, funcional, pero!!!!... tiene un cierto parpadeo, cosa que no me gusto, pero esta buena la idea…
Luego… viendo las preguntas del foro, la típica pregunta… un TextBox que solo acepte números… bien, ya había descargado un control de CodeProject que tiene esta funcionalidad, para usarlo en mis desarrollos, pero cuando decidí usarlo, en mi ordenador funciona bien pero ya en el ordenador del cliente me genera una excepción y me vota el sistema “no con esto digo que el control no funcione, funciona pero no tenia tiempo para averiguar cual es el problema ya que mi sistema operativo es Windows Vista y el del cliente es Windows XP, no deberia ser problema, pero me fallo ya en la cancha”, así que revisándolo para ver cómo aplicar esta funcionalidad en mi control, me dije… bueno, voy a escribirlo de cero y voy hacer que trabaje con la configuración regional del Window’s y en lugar de crear varios controles, usar uno solo, así que de aquí nació la idea de agregarla una propiedad más al control la cual es “MaskType” la cual por el momento está limitada a los siguientes tipos: None, Currency, Numeric, Percent e Integer y viendo cómo funcionan otros controles de terceros, veremos si lo volvemos más flexible la parte de el formato a utilizar ya que interna mente usa el formato para cada caso: Currency “C”, Numeric “N”, Percent “P”.
Ahora, hasta donde lo he probado creo que está listo, así que prepare este proyecto de ejemplo para que lo puedan probar y si es de vuestro agrado usarlo en vuestro desarrollo y no está de más que hagan sus comentarios al respecto sobre que mejorar, que agregar o que quitar….

Imagen de ejemplo:
TextEditorDemo
Propiedades
AutoHeight Permite cambia el alto del control, valor predeterminado true
Buttons
Permite agregar y remover los botones que serán mostrados dentro del control TextEditor, tipo de propiedad TextEditorButtonCollection.
EditValue
Propiedad que almacenara el valor sin formato que se mostrara en la propiedad Text ya formateado en los casos de usar MarkType en Currency, Numeric, Percent e Integer.
EnterMoveNextControl
Permite indicar si el foco del control se moverá al siguiente control según el TAB orden al presionar la tecla ENTER, valor predeterminado true.
Image
Permite insertar una imagen que será mostrada dentro del control TextEditor.
ImageAlignment
Indica la posición donde se mostrara la Imagen dentro del Control, valor predeterminado Right
MaskType
Permite indicar el modo de entrada de datos que permitirá el control, valor predeterminado MaskType.None
WaterMarkFont
Permite indicar el tipo de letra que se usara para mostrar el texto como marca de agua.
WaterMarkForecolor Permite indicar el color del texto que se mostrara como marca de agua.
WaterMarkText
Permite indicar el texto que se mostrara como marca de agua.
Enum MaskType
None
Permite una entrada de datos sin restricciones
Currency
Permite una entrada de datos de solo números con un formato de moneda usando el signo de moneda definido en la configuración regional del sistema operativo.
Numeric
Permite una entrada de datos de solo números con un formato de número definido en la configuración regional del sistema operativo.
Percent
Permite una entrada de datos de solo números con un formato de porcentaje definido en la configuración regional del sistema operativo.
Integer
Permite una entrada de datos de solo números sin formato, sin separador de miles y separador de decimales.
Eventos
ButtonClick
Se ejecuta al presionar y soltar el mouse sobre cualquiera de los botones del control TextEditor, recibiendo un argumento del tipo ButtonPressedEventArgs que contiene data relacionada al evento.
Button Provee información relacionada con el botón presionado.
EditValueChanged Se ejecuta al cambiar el valor de la propiedad EditValue.

TextEditorButton

Representa un botón dentro del control TextEditor.
Propiedades
Enabled
Indica si el botones está disponible para interactuar con el usuario, valor predeterminado true
Image
Permite agregar una imagen que será mostrada dentro del botón
IsLeft
Permite indicar si el botón debe mostrarse al lado izquierdo del Control, valor predeterminado false
Tag
Permite agregar información adicional al botón, valor predeterminado null (Nothing en Visual Basic)
Text
Permite agregar un texto que será mostrado dentro del botón
Visible
Permite indicar si el botón esta visible al usuario, valor predeterminado true
Width
Permite indicar el ancho del botón, valor predeterminado -1

Artículos Relacionados:

TextBox con borde personalizado
TextBox con Icon/Imagen
DataGridViewTextEditorColumn

viernes, 13 de mayo de 2011

NetBarControl


Actualización.
NetBarControl - Description Item Style (New)


NetBarControl_1

NetBarControl (Outlook Bar) es uno de los controles que muchas veces buscamos para usar en nuestras aplicaciones, pero siempre encontramos en internet versiones pagables y tal vez no contamos con el presupuesto esperado como para comprar uno y las versiones gratis que se logran encontrar, pues como son gratis no implementan en su totalidad la funcionalidad que esperamos encontrar en un control de este tipo.
Antes de comenzar a escribir este control dedique tiempo en buscar uno por internet que tuviera toda la funcionalidad o por lo menos una interfaz disponible en modo de diseño, pero, no logre encontrar uno, así que me propuse crearlo como a mí me gustaría que funcionara uno gratis y al final llegue a la conclusión de ¿Porque no hay uno completo, gratis y que incluya el código fuente? y la respuesta es: No es fácil, pero tampoco es cosa de otro mundo. Con esto no digo que otro programador no lo pueda hacer o que los ejemplos encontrados sean malos o que no puedan llegar a tener esta complejidad, claro que podrían
Bien, Contribuyendo a la comunidad he puesto el control que he creado y llamado NetBarControl para que lo puedan descargar, pero… no incluye el código fuente, no por el momento
En fin… espero les guste este control, así que aquí les dejo un proyecto donde pueden evaluar el producto y dejar sus comentarios
FreeDownload2
Esta es la primera versión, según sus comentarios, veremos si le seguimos agregando más funcionalidades como ser: Skins y Estilos, como también mejoras al control.

Veamos las propiedades y controles relacionados al control.

Propiedades de NetBarControl

ActiveGroup
Muestra el grupo activo actualmente.
CaptionFont
Permite modificar el tipo de letra a utilizar en el titulo del Control
Groups
Permite Agregar, Modificar y Eliminar los grupos que contendra el control
GroupsFont
Permite definir el tipo de letra utilizado en los controles NetBarGroup.
ItemsFont
Permite definir el tipo de letra utilizado en los controles NetBarItem
PanelState
Propiedad que indica el estado actual del control, los cuales son: Expande/Collapsed
ShowExpandButton
true/false Propiedad que indica si el control debe mostrar u ocultar el boton para Expandir o Contraer el control.
ShowHorizontalSplitter
true/false Propiedad que indica si se debe de mostrar el control Splitter horizontal que permite redimencionar el control.
ShowOverflowPanel
true/false Propiedad que indica si se debe mostrar el panel de desbordamiento de grupos.
ShowOverflowButton
true/false, Propiedad que permite mostrar u ocultar el menú en el panel de desbordamiento.
ShowPopupShadow
true/false, Propiedad que permite mostrar u ocultar sombra en la ventana emergente cuando el control esta contraido (Collapsed)
ShowVerticalSplitter
true/false, Propiedad que permite mostrar u ocultar el control splitter vertical para ocultar o mostrar grupos.


NetBarGroup

Font
Tipo de letra que se utilizara para dibujar el Texto del grupo.
ForeColor
Color del texto del grupo
Items
NetBarItemCollection, permite agregar, modificar y eliminar los items que se mostraran dentro del grupo.
ShowInOverflowPanel
true/false, indica si el grupo se debe de mostrar en el panel de desbordamiento.
SmallImage Imagen que representa el grupo
Style
Propiedad que permite cambiar el estilo del grupo, como ser: ItemList,
LargeItemList
ControlContainer
Tag
Propiedad para asociar información adicional al grupo
Text Texto asociado con el grupo
Visible
true/false, Determina si el grupo es visible u oculto al usuario.

NetBarItem


Enabled
true/false, Indica si el Item esta habilitado o desabilitado.
Font
Tipo de letra usada para mostrar el texto en el Item.
ForeColor
El color usando para mostrar el texto.
LargeImage
Imagen utilizada para mostrar cuando el Grupo del Item esta en estilo LargeItemList
SmallImage
Imagen que se mostrara al lado izquierdo del texto cuando el Grupo al cual esta asociado el Item utilize el estilo “ItemList
Tag Propiedad para asociar información adicional al control
Text Texto a mostrar en el control
Visible
true/false, Indicar si el control debe ser visible u oculto al usuario.

Pantallas en modo de Diseño:

En el SmartTasks podemos encontrar de modo rapido algunas de las propiedades importantes del control.
image

image
image
¿Como agregar un nuevo grupo en tipo de ejecución por código?
if (netBarControl1.Groups["groupContainer"] != null) 
{
 MessageBox.Show("Grupo ya existe"); 
 return; 
}

Label label = new Label() 
{ 
 Text = "Ingreso texto:",
 Dock = DockStyle.Top 
};
TextBox tbox = new TextBox() 
{ 
 Multiline = true, 
 Dock = DockStyle.Fill 
};

NetBarGroup group = netBarControl1.Groups.Add(NetBarGroupStyle.ControlContainer); 
group.Text = "Grupo de prueba";
group.Name = "groupContainer";
group.ControlContainer.Padding = new Padding(10); 
group.ControlContainer.Controls.AddRange(new Control[] { tbox, label }); 

¿Como agregar un nuevo Item en ejecución por código?

if (netBarControl1.ActiveGroup.Style == NetBarGroupStyle.ControlContainer) 
{ 
 MessageBox.Show("No puede agregar Items a este grupo"); 
 return; 
}

NetBarItem item = new NetBarItem(); 
item.Text = "Item de Prueba";
item.Name = "itemPrueba";
item.ItemClick += new EventHandler(netBarItem_ItemClick); 
netBarControl1.ActiveGroup.Items.Add(item);


Actualizaciones





Miércoles, 18/May/2011



  • Se corrigio problema al remover Item o Grupo en tiempo de diseño desde el menú de acceso rapido.





Lunes, 07/Nov/2011



  • Se ha agregado la funcionalidad en tiempo de diseño para que al momento de precionar doble clic sobre un item crear/abrir el evento “ItemClick”.