domingo, 29 de noviembre de 2015

Windows Forms. DataGridView. Columna para números con decimales (I)

A raíz de la publicación del artículo DataGridView. Columna que acepta sólo números. un par de lectores del blog me cuestionaron sobre la forma de modificar el ejemplo para  añadir la posibilidad de introducir números decimales.

Con el objetivo de responder a esta duda vamos a ver cómo podemos definir una columna a la que le podamos indicar no sólo el número de decimales a mostrar, si no también el separador decimal a utilizar a la hora de mostrar los valores.

Como en el ejemplo de la columna para números enteros voy a crear dos nuevas clases: una clase NumericGridColumn para definir la columna y que heredará de DataGridViewColumn, y otra clase NumericGridCell para la celda y que heredará de DataGridViewTextBoxCell.

using System;
using System.ComponentModel;
using System.Globalization;
using System.Windows.Forms;

namespace GridExtension
{
    public class NumericGridColumn : DataGridViewColumn
    {

    }

    public class NumericGridCell: DataGridViewTextBoxCell
    {

    }

}

En primer lugar voy a crear dos nuevas propiedades en la clase NumericGridColumn: una propiedad DecimalSeparator que permitirá definir el carácter a utilizar como separador decimal, y una propiedad DecimalDigits que indicará el número de decimales permitido.

Crearé también una tercera propiedad NumberFormat para uso interno que devolverá el objeto NumberFormatInfo a utilizar para formatear los números de las celdas. Si no se han indicado valores para las propiedades DecimalSeparator y DecimalDigits la propiedad NumberFormat utilizará los valores definidos para la cultura actual.

    public class NumericGridColumn : DataGridViewColumn
    {
        private NumberFormatInfo _numberFormat;
        private string _decimalSeparator;
        private int _decimalDigits = -1;

        [Category("Appearance")]
        public string DecimalSeparator {
            get {
                if (string.IsNullOrEmpty(_decimalSeparator))
                    return CultureInfo.CurrentUICulture.NumberFormat.NumberDecimalSeparator;
                else
                    return _decimalSeparator;
            }
            set
            {
                if (value.Length != 1)
                    throw new ArgumentException("El separador decimal debe ser un único caracter");
                _decimalSeparator = value;
            }
        }

        [Category("Appearance")]
        public int DecimalDigits {
            get
            {
                if (_decimalDigits < 0)
                    return CultureInfo.CurrentUICulture.NumberFormat.NumberDecimalDigits;
                else
                    return _decimalDigits;
            }
            set { _decimalDigits = value; }
        }

        internal NumberFormatInfo NumberFormat
        {
            get
            {
                if (_numberFormat == null)
                    _numberFormat = new NumberFormatInfo();
                _numberFormat.NumberDecimalSeparator = DecimalSeparator;
                _numberFormat.NumberDecimalDigits = DecimalDigits;
                return _numberFormat;
            }
        }
    }




Para completar el código de la columna en el constructor de la clase NumericGridColumn voy a llamar al constructor de DataGridViewColumn pasándole una instancia de NumericGridCell como plantilla de celda. Voy a sobrescribir también la propiedad CellTemplate para comprobar que la celda que se establece como plantilla es del tipo NumericGridCell.

Por último sobrescribiré el método Clone para que se pasen los valores de las propiedades DecimalSeparator y DecimalDigits cuando se cree una columna clonando una ya existente.

        public NumericGridColumn():base (new NumericGridCell()) { }

        public override DataGridViewCell CellTemplate
        {
            get
            {
                return base.CellTemplate;
            }
            set
            {
                if (value != null &&
                        !value.GetType().IsAssignableFrom(typeof(NumericGridCell)))
                    throw new InvalidCastException("Debe especificar una instancia de NumericGridCell");
                base.CellTemplate = value;
            }
        }

        public override object Clone()
        {
            NumericGridColumn newColumn = (NumericGridColumn)base.Clone();
            newColumn.DecimalSeparator = DecimalSeparator;
            newColumn.DecimalDigits = DecimalDigits;
            return newColumn;
        }

Artículo siguiente:
Windows Forms. DataGridView. Columna para números con decimales (y II)

1 comentario:

  1. Gracias Asiel, pero parece que falta la clase NumericGridCell, ya que no hace nada el eontrol, hace exactamente lo que hace la columna Integer.Es decir, no da el formato de números con puntos y decimales
    Lo puedes subir ?
    Es urgente
    Si quieres lo puedes enciar a mi email tambien.
    Gracias

    ResponderEliminar