none
ComboBox dentro de columna del DataGridView RRS feed

  • Pregunta

  • Hola

    Trabajo en una app de escritorio Windows Forms en el cual trabajo con un objeto DGV en el cual tengo una columna de tipo ComboBox 

    El problema es cuando cargo el ComboBox no me carga el primer item que dice <<Seleccione>> para poder ver los items tengo que hacer click en el combo a diferencia del ComboBox tradicional carga el primer item.

    El ComboBox del DGV lo cargo de la siguiente manera.

    DataGridViewComboBoxColumn cboColImpuesto = dgvDetCatalogo.Columns["colImpuesto"] as DataGridViewComboBoxColumn;
                cboColImpuesto.DataSource = _saCatalogo.GetEnumDescription<IncluyeImpuestoType>(true).ToList();
                cboColImpuesto.DisplayMember = "Descripcion";
                cboColImpuesto.ValueMember = "Id";

    Si tuviera una propiedad SelectedIndex si le podría decir que cargue el primero, ¿De que manera pudo hacer que cargue el primer item sin que tenga que interactuar con el combo?.

    Saludos!


    Pedro Ávila
    "El hombre sabio querrá estar siempre con quien sea mejor que él."
    Lima - Perú

    sábado, 7 de julio de 2018 8:16

Respuestas

  • Yo acabo de hacer la prueba en un proyecto de prueba de Windows Forms en VS 2017.

    Defino un enum:

        public enum SomeEnum
        {
            Invalid = 0,
            OptionA = 1,
            OptionB = 2
        }
    

    Luego defino un objeto entidad que tiene una propiedad de este tipo de enum:

        public class Person
        {
            public long Id { get; set; }
            public string FirstName { get; set; }
            public string LastName { get; set; }
            public Gender Gender { get; set; }
            public SomeEnum SomeProperty { get; set; }
        }
    

    Luego defino columnas en el DGV a través del editor de columnas, que generan el siguiente código en el archivo designer:

                this.Id = new System.Windows.Forms.DataGridViewTextBoxColumn();
                this.FirstName = new System.Windows.Forms.DataGridViewTextBoxColumn();
                this.LastName = new System.Windows.Forms.DataGridViewTextBoxColumn();
                this.Gender = new System.Windows.Forms.DataGridViewTextBoxColumn();
                this.SomeEnum = new System.Windows.Forms.DataGridViewComboBoxColumn();
                // 
                // Id
                // 
                this.Id.DataPropertyName = "Id";
                this.Id.HeaderText = "ID";
                this.Id.Name = "Id";
                this.Id.ReadOnly = true;
                // 
                // FirstName
                // 
                this.FirstName.DataPropertyName = "FirstName";
                this.FirstName.HeaderText = "First Name";
                this.FirstName.Name = "FirstName";
                // 
                // LastName
                // 
                this.LastName.DataPropertyName = "LastName";
                this.LastName.HeaderText = "Last Name";
                this.LastName.Name = "LastName";
                // 
                // Gender
                // 
                this.Gender.DataPropertyName = "Gender";
                this.Gender.HeaderText = "Gender";
                this.Gender.Name = "Gender";
                this.Gender.ReadOnly = true;
                // 
                // SomeEnum
                // 
                this.SomeEnum.DataPropertyName = "SomeProperty";
                this.SomeEnum.HeaderText = "Some Property";
                this.SomeEnum.Name = "SomeEnum";
                this.SomeEnum.ReadOnly = true;
            private System.Windows.Forms.DataGridViewTextBoxColumn Id;
            private System.Windows.Forms.DataGridViewTextBoxColumn FirstName;
            private System.Windows.Forms.DataGridViewTextBoxColumn LastName;
            private System.Windows.Forms.DataGridViewTextBoxColumn Gender;
            private System.Windows.Forms.DataGridViewComboBoxColumn SomeEnum;
    

    Luego en el evento Load del formulario obtengo la columna tipo ComboBox y asigno un DataSource para los items posibles de lista, que simplemente es una lista completa de los valores en el enum.  Finalmente, creo una pequeña lista de objetos tipo Person y solamente asigno a uno de ellos un valor a la propiedad SomeProperty.

            private void Form1_Load(object sender, EventArgs e)
            {
                dgv.AutoGenerateColumns = false;
                DataGridViewComboBoxColumn col = dgv.Columns["SomeEnum"] as DataGridViewComboBoxColumn;
                col.DataSource = Enum.GetValues(typeof(Domain.SomeEnum));
                List<Domain.Person> persons = new List<Domain.Person>();
                persons.Add(new Domain.Person()
                {
                    Id = 1,
                    FirstName = "Jessica",
                    LastName = "Alba",
                    Gender = new Domain.Gender()
                    {
                        Id = 1,
                        Name = "Femenino"
                    },
                    SomeProperty = Domain.SomeEnum.OptionA
                });
                persons.Add(new Domain.Person()
                {
                    Id = 1,
                    FirstName = "José",
                    LastName = "Ramírez",
                    Gender = new Domain.Gender()
                    {
                        Id = 2,
                        Name = "Masculino"
                    }
                });
                dgv.DataSource = persons;
            }
    

    Sin más por hacer, corro el programa.  La grilla muestra  los valores "OptionA" e "Invalid" preseleccionados en cuanto el formulario se muestra.  No hay más que hacer, no hay trucos bajo la manga.

    Haha, ya vi su error.  Después de que escribí toooodo lo anterior:  Su error está en el hecho de que la propiedad UniversalExtend.Id (la propiedad que se vincula al combo a través de ValueMember) es de tipo Int.  Tiene que ser del tipo del enum.  Declare UniversalExtend a manera de genérico.

    public class UniversalExtend<TEnum>
    {
        public TEnum Id { get; set; }
        ...
    }


    Jose R. MCP
    My GIT Repositories | Mis Repositorios GIT

    • Marcado como respuesta Pedro Ávila lunes, 16 de julio de 2018 11:44
    martes, 10 de julio de 2018 0:10
    Moderador

Todas las respuestas

  • Deleted
    sábado, 7 de julio de 2018 13:00
  • Prueba a manejar este evento

    void dataGridView1_EditingControlShowing(object sender, DataGridViewEditingControlShowingEventArgs e)
            {
                ComboBox cmb = e.Control as ComboBox; 
                if (cmb != null)
                {
                    
                    cmb.SelectedIndex = -1;
                }
            }


    Si se solucionó tu consulta no olvides marcar la respuesta. Si te ayudó, vótala como útil. Saludos

    sábado, 7 de julio de 2018 18:19
    Moderador
  • Concuerdo con la anotación de Sergio cuando dice que el valor seleccionado depende del valor de la propiedad del objeto que representa la fila.

    Veo que es un enum, así que supongo que el objeto vinculado a esa grilla tiene una propiedad cuyo tipo es ese enum.  Ese enum debe tener una selección "inválida", que para mis enums normalmente tienen el valor cero.

    ¿Esto que le describí le es familiar en el contexto de su aplicación?


    Jose R. MCP
    My GIT Repositories | Mis Repositorios GIT

    sábado, 7 de julio de 2018 18:49
    Moderador
  • Hola @webJose

    ¿Esto que le describí le es familiar en el contexto de su aplicación?

    Totalmente

    public IEnumerable<UniversalExtend> GetEnumDescription<T>(bool insertFirstItem)
            {
                var descriptions = new List<UniversalExtend>();
    
                var query2 = (from T v in Enum.GetValues(typeof(T)) select v);
    
                foreach (var element in query2)
                {
                    var item = new UniversalExtend();
    
                    item.Id = (int)Enum.Parse(typeof(T), Enum.GetName(typeof(T), element));
                    item.Descripcion = GetDescription(element);
                    descriptions.Add(item);
                }
    
                if (insertFirstItem) descriptions.Insert(0, new UniversalExtend { Id = -1, Descripcion = "<<<Seleccione>>>" });
    
                return descriptions;
            }
    
            private string GetDescription(object enumValue)
            {
    
                FieldInfo fi = enumValue.GetType().GetField(enumValue.ToString());
    
                object[] attrs = fi?.GetCustomAttributes(typeof(DescriptionAttribute), true);
                if (attrs != null && attrs.Length > 0)
                {
                    return ((DescriptionAttribute)attrs[0]).Description;
                }
                return enumValue.ToString();
            }

    Me parece que el combo que tengo en el DataGridView lo tenga que cargar con un for hacer algún truco para que salga cargado el primer elemento por que se ve vació hasta hacer click.

    Saludos!


    Pedro Ávila
    "El hombre sabio querrá estar siempre con quien sea mejor que él."
    Lima - Perú

    lunes, 9 de julio de 2018 13:36
  • Hola @Sergio

    He probado lo que me indicaste y no carga el primer item como lo hace en un ComboBox normal.

    Lo que deseo hacer es lo que muestro en la imagen en la cual cargo un ComboBox y por default me carga un item que se llama Seleccione. 

    Lo mismo pretendo hacer en el combo del DGV

    Saludos!


    Pedro Ávila
    "El hombre sabio querrá estar siempre con quien sea mejor que él."
    Lima - Perú


    lunes, 9 de julio de 2018 13:37
  • hola

    >>Lo mismo pretendo hacer en el combo del DGV

    aqui

    [DataGridView] - Uso del DataGridViewComboBoxColum

    explico como podrias lograrlo, valida el Load del form y veras como desde codigo accedes a la columna del tipo combo del grid para cargar su contenido

    basicamente haces

        DataGridViewComboBoxColumn comboboxColumn = dataGridView1.Columns["Medida"] as DataGridViewComboBoxColumn;
     
        comboboxColumn.DataSource = MedidasDAL.GetAllMedidas();
        comboboxColumn.DisplayMember = "Descripcion";
        comboboxColumn.ValueMember = "Id";

    por supuesto al obtener todos los items debes agregar el adicional que diga "seleccione"

    >>¿De que manera pudo hacer que cargue el primer item sin que tenga que interactuar con el combo?.

    no entiendo a que te refieres con "interacturar" ? te refieres al codigo o el usuario

    saludos


    Leandro Tuttini

    Blog
    MVP Profile
    Buenos Aires
    Argentina


    lunes, 9 de julio de 2018 14:35
  • Hola @Leandro

    Justamente lo que tengo implementado es con el articulo que me acabas de compartir.

    explico como podrias lograrlo, valida el Load del form y veras como desde codigo accedes a la columna del tipo combo del grid para cargar su contenido

    Si lo he probado en el evento load del formulario y si carga los tres ComboBox

    private void LoadDgvDetCatalogo()
            {
                DataGridViewComboBoxColumn cboColImpuesto = dgvDetCatalogo.Columns["colImpuesto"] as DataGridViewComboBoxColumn;
                cboColImpuesto.DataSource = _saCatalogo.GetEnumDescription<IncluyeImpuestoType>(true).ToList();
                cboColImpuesto.DisplayMember = "Descripcion";
                cboColImpuesto.ValueMember = "Id";
    
                DataGridViewComboBoxColumn cboColUMedida = dgvDetCatalogo.Columns["colMedida"] as DataGridViewComboBoxColumn;
                cboColUMedida.DataSource =
                    _saUnidadMedida.SelectList(
                        x => new UniversalExtend() { Id = x.UnidadMedidaId, Descripcion = x.Abreviacion }).ToList();
                cboColUMedida.DisplayMember = "Descripcion";
                cboColUMedida.ValueMember = "Id";
    
                DataGridViewComboBoxColumn cboColMoneda = dgvDetCatalogo.Columns["colMoneda"] as DataGridViewComboBoxColumn;
                cboColMoneda.DataSource =
                    _saMoneda.SelectList(x => new UniversalExtend() { Id = x.MonedaId, Descripcion = x.Nombre }).ToList();
                cboColMoneda.DisplayMember = "Descripcion";
                cboColMoneda.ValueMember = "Id";
            }

    El detalle es que los ComboBox si están cargados pero para ver lo que hay que escoger en el combobox tienes que hacer clik en el combobox para que te muestre los items que están cargados. No como el comobobox tradicional que cuando lo cargas te muestra el primer elemento que esta en la posición 0 en mi caso <<<Seleccione>>>. No se si me he explicado bien.

    Te muestro mi grid cargado de elementos para que veas que a simple vista pareciera que no esta cargado nada en los combos.

    Saludos!


    Pedro Ávila
    "El hombre sabio querrá estar siempre con quien sea mejor que él."
    Lima - Perú


    lunes, 9 de julio de 2018 15:14
  • no intentaste poniendo

    DataGridViewComboBoxColumn cboColImpuesto = dgvDetCatalogo.Columns["colImpuesto"] as DataGridViewComboBoxColumn; cboColImpuesto.DataSource = _saCatalogo.GetEnumDescription<IncluyeImpuestoType>(true).ToList(); cboColImpuesto.DisplayMember = "Descripcion"; cboColImpuesto.ValueMember = "Id";

    cboColImpuesto.SelextedIndex = 0;

    asi indicarias que por defecto se muestre el primero

    ojo que quizas vas a tener que acceder al value de la celda usando

    dgvDetCatalogo.Rows[0].Cells[3].Value = 0; // esta es la celda de la columna medida


    o sea en el value indicas que item se selecciona

    saludos


    Leandro Tuttini

    Blog
    MVP Profile
    Buenos Aires
    Argentina


    lunes, 9 de julio de 2018 15:25
  • Leandro

    El ComboBox del DGV no tiene en sus propiedades SelectedIndex por eso no he podido hacer lo que me sugieres.

    Saludos


    Pedro Ávila
    "El hombre sabio querrá estar siempre con quien sea mejor que él."
    Lima - Perú

    lunes, 9 de julio de 2018 15:40
  • Se podría hacer algo como esto

    if (dgvDetCatalogo.Rows[0].Cells[4].Value.ToString() == String.Empty)
                {
                    
                }

    https://social.msdn.microsoft.com/Forums/windows/en-US/57df7b19-4929-47e3-9793-9a6fba278595/set-selected-index-of-combobox-column-in-datagridview?forum=winformsdesigner

    Saludos!


    Pedro Ávila
    "El hombre sabio querrá estar siempre con quien sea mejor que él."
    Lima - Perú

    lunes, 9 de julio de 2018 16:19
  • >>El ComboBox del DGV no tiene en sus propiedades SelectedIndex por eso no he podido hacer lo que me sugieres.

    creo que es mejor usar el Value de la celda

    >>Se podría hacer algo como esto

    si puedes acceder al valor de la celda, pero el value no sera empty, sino la seleccion del combo, creo que devolveria un -1, recuerda que la celda es un combo en realidad

    pon un break en el codigo y evalua que retorna en el value

    saludos


    Leandro Tuttini

    Blog
    MVP Profile
    Buenos Aires
    Argentina


    lunes, 9 de julio de 2018 17:10
  • Yo acabo de hacer la prueba en un proyecto de prueba de Windows Forms en VS 2017.

    Defino un enum:

        public enum SomeEnum
        {
            Invalid = 0,
            OptionA = 1,
            OptionB = 2
        }
    

    Luego defino un objeto entidad que tiene una propiedad de este tipo de enum:

        public class Person
        {
            public long Id { get; set; }
            public string FirstName { get; set; }
            public string LastName { get; set; }
            public Gender Gender { get; set; }
            public SomeEnum SomeProperty { get; set; }
        }
    

    Luego defino columnas en el DGV a través del editor de columnas, que generan el siguiente código en el archivo designer:

                this.Id = new System.Windows.Forms.DataGridViewTextBoxColumn();
                this.FirstName = new System.Windows.Forms.DataGridViewTextBoxColumn();
                this.LastName = new System.Windows.Forms.DataGridViewTextBoxColumn();
                this.Gender = new System.Windows.Forms.DataGridViewTextBoxColumn();
                this.SomeEnum = new System.Windows.Forms.DataGridViewComboBoxColumn();
                // 
                // Id
                // 
                this.Id.DataPropertyName = "Id";
                this.Id.HeaderText = "ID";
                this.Id.Name = "Id";
                this.Id.ReadOnly = true;
                // 
                // FirstName
                // 
                this.FirstName.DataPropertyName = "FirstName";
                this.FirstName.HeaderText = "First Name";
                this.FirstName.Name = "FirstName";
                // 
                // LastName
                // 
                this.LastName.DataPropertyName = "LastName";
                this.LastName.HeaderText = "Last Name";
                this.LastName.Name = "LastName";
                // 
                // Gender
                // 
                this.Gender.DataPropertyName = "Gender";
                this.Gender.HeaderText = "Gender";
                this.Gender.Name = "Gender";
                this.Gender.ReadOnly = true;
                // 
                // SomeEnum
                // 
                this.SomeEnum.DataPropertyName = "SomeProperty";
                this.SomeEnum.HeaderText = "Some Property";
                this.SomeEnum.Name = "SomeEnum";
                this.SomeEnum.ReadOnly = true;
            private System.Windows.Forms.DataGridViewTextBoxColumn Id;
            private System.Windows.Forms.DataGridViewTextBoxColumn FirstName;
            private System.Windows.Forms.DataGridViewTextBoxColumn LastName;
            private System.Windows.Forms.DataGridViewTextBoxColumn Gender;
            private System.Windows.Forms.DataGridViewComboBoxColumn SomeEnum;
    

    Luego en el evento Load del formulario obtengo la columna tipo ComboBox y asigno un DataSource para los items posibles de lista, que simplemente es una lista completa de los valores en el enum.  Finalmente, creo una pequeña lista de objetos tipo Person y solamente asigno a uno de ellos un valor a la propiedad SomeProperty.

            private void Form1_Load(object sender, EventArgs e)
            {
                dgv.AutoGenerateColumns = false;
                DataGridViewComboBoxColumn col = dgv.Columns["SomeEnum"] as DataGridViewComboBoxColumn;
                col.DataSource = Enum.GetValues(typeof(Domain.SomeEnum));
                List<Domain.Person> persons = new List<Domain.Person>();
                persons.Add(new Domain.Person()
                {
                    Id = 1,
                    FirstName = "Jessica",
                    LastName = "Alba",
                    Gender = new Domain.Gender()
                    {
                        Id = 1,
                        Name = "Femenino"
                    },
                    SomeProperty = Domain.SomeEnum.OptionA
                });
                persons.Add(new Domain.Person()
                {
                    Id = 1,
                    FirstName = "José",
                    LastName = "Ramírez",
                    Gender = new Domain.Gender()
                    {
                        Id = 2,
                        Name = "Masculino"
                    }
                });
                dgv.DataSource = persons;
            }
    

    Sin más por hacer, corro el programa.  La grilla muestra  los valores "OptionA" e "Invalid" preseleccionados en cuanto el formulario se muestra.  No hay más que hacer, no hay trucos bajo la manga.

    Haha, ya vi su error.  Después de que escribí toooodo lo anterior:  Su error está en el hecho de que la propiedad UniversalExtend.Id (la propiedad que se vincula al combo a través de ValueMember) es de tipo Int.  Tiene que ser del tipo del enum.  Declare UniversalExtend a manera de genérico.

    public class UniversalExtend<TEnum>
    {
        public TEnum Id { get; set; }
        ...
    }


    Jose R. MCP
    My GIT Repositories | Mis Repositorios GIT

    • Marcado como respuesta Pedro Ávila lunes, 16 de julio de 2018 11:44
    martes, 10 de julio de 2018 0:10
    Moderador