Principales respuestas
ComboBox dentro de columna del DataGridView

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ú
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
Todas las respuestas
-
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
-
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 -
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ú -
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ú- Editado Pedro Ávila lunes, 9 de julio de 2018 13:50
-
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
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- Editado Leandro TuttiniMVP lunes, 9 de julio de 2018 14:38
-
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ú- Editado Pedro Ávila 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- Editado Leandro TuttiniMVP lunes, 9 de julio de 2018 15:26
-
-
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ú -
>>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- Editado Leandro TuttiniMVP 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