Pregunta

Estoy tratando de vincular un DataGridViewComboBoxColumn a una instancia de Foo, pero cuando configuré un valor en la cuadrícula obtuve un ArgumentException que me decía que no podía convertir de String a Foo.

var data = (from item in someTable
            select new { Foo = item.foo, Bar = item.Bar }).ToList();
grid.DataSource = data;
column.DataPropertyName = "Foo";
column.DataSource = (from foo in Foo select foo).ToList (); //foo is an instance of Foo
column.DisplayMember = "SomeNameField"; //Foo.SomeNameField contains a description of the instance

¿Me estoy perdiendo algo? ¿es posible enlazar datos a un objeto complejo?

UPDATE:

Implementé un TypeConverter y anulé CanConvertFrom, CanConvertTo, ConvertTo, ConvertFrom. Ahora me estoy poniendo

  

FormatException: el valor DataGridViewComboBoxCell no es válido

¿Alguna idea?

¿Fue útil?

Solución

Te falta una pieza posible.

column.DataPropertyName = "Foo";
column.DisplayMember = "SomeNameField"; 
column.ValueMember = "Bar"; // must do this, empty string causes it to be 
                            // of type string, basically the display value
                            // probably a bug in .NET
column.DataSource = from foo in Foo select foo;
grid.DataSource = data;

ACTUALIZACIÓN:

En realidad, después de leer su pregunta nuevamente, creo que se enfrenta a ese error señalado. Desafortunadamente, no hay forma de hacerlo devolver el objeto enlazado sin usar un TypeDescriptor / TypeConverter / BindingSource personalizado.

Respuesta para vincular a un objeto complejo. No por defecto. Escribí una muy buena para mi proyecto actual. Esto implica hacer un TypeDescriptor / TypeConverter / BindingSource personalizado que devuelva todas las propiedades anidadas. Otro 'error', no puedes usar '.' para un separador de miembros, tuve que recurrir a ':' en su lugar.

Otros consejos

DataGridViewComboBoxColumn siempre debe tener todos los valores posibles en la lista de elementos del cuadro combinado o arrojará " FormatException: el valor DataGridViewComboBoxCell no es válido " ;.

Si está intentando recuperar los valores elegidos de una columna de cuadro combinado, puede controlar el evento DataGridView CellParsing y obtener el elemento seleccionado de DataGridView.EditingControl porque se configurará para editar el control desde la columna editada. Aquí hay un ejemplo:

private void dataGridView1_CellParsing(object sender, 
 DataGridViewCellParsingEventArgs e) {
   if (dataGridView1.CurrentCell.OwningColumn is DataGridViewComboBoxColumn) {
       DataGridViewComboBoxEditingControl editingControl = 
                (DataGridViewComboBoxEditingControl)dataGridView1.EditingControl;
       e.Value = editingControl.SelectedItem;
       e.ParsingApplied = true;
   }
}

También puede personalizar la forma en que se muestran sus objetos en cada celda manejando el Evento de formato de celda, aquí hay un código que se muestra aString para cualquier objeto o interfaz.

private void dataGridView1_CellFormatting(object sender, 
    DataGridViewCellFormattingEventArgs e) {
        if (e.Value != null) {
            e.Value = e.Value.ToString();
            e.FormattingApplied = true;
        }
    } 

Maneja estos dos eventos debería ser suficiente para mostrar y editar datos dentro de cualquier objeto comercial y es más fácil escribir convertidores de tipo. Para este trabajo, configure DataGridView y su columna de cuadro combinado de la siguiente manera:

var data = (from item in someTable
        select new { Foo = item.foo, Bar = item.Bar }).ToList();
grid.DataSource = data;
column.DataPropertyName = "Foo";
column.DataSource = (from foo in Foo select foo).ToList ();

No es necesario establecer la propiedad DisplayMember o ValueMember, solo asegúrese de que su lista de fuentes de datos del cuadro combinado tenga todos los valores posibles para Foo.

Espero que sea de ayuda.

En realidad, puede usar un tipo complejo en DataGridViewComboBoxColumn .

Por ejemplo:

DataGridViewComboBoxColumn.DataPropertyName = "ValueMode";
DataGridViewComboBoxColumn.DisplayMember = "Label";
DataGridViewComboBoxColumn.ValueMember = "Self"; *
DataGridViewComboBoxColumn.ValueType = typeof(ValueModeItem);

Self es:

public ValueModeItem Self
{
    get
    {
        return this;
    }
}

Muy importante: es necesario anular el método 'Igual' de un tipo complejo. En mi caso:

public override bool Equals(object obj)
{
    if (obj is ValueModeItem && obj != null)
    {
        if (...)
            return true;
    }
    return false;
}

Estaba constantemente enfrentando el mismo problema hasta que descubrí que no puede establecer el DisplayMember del DataGridViewComboBoxCell sin configurar el ValueMember . < br> Del mismo modo, establecer el ValueMember y no el DisplayMember también es un error, debe definir ninguno o ambos.

Su modelo es Foo, y ciertamente desea que el Valor del ComboBox sea el elemento en sí. Para hacer esto, la forma más sencilla es crear una Propiedad en tu foo, devolviéndola.

public class Foo
{
    ...
    public Foo This { get {return this; } }
}

Entonces los enlaces se convierten en:

column.DataPropertyName = "Foo";
column.DataSource = (from foo in Foo select foo).ToList (); //foo is an instance of Foo
column.DisplayMember = "SomeNameField"; //Foo.SomeNameField contains a description of the instance
column.ValueMember = "This";

Esto debería funcionar, y el valor de la celda debería ser del tipo Foo como se esperaba.

Una referencia interesante: Problemas con DataGridViewComboBoxColumn

  

Sin embargo, DataGridViewComboBoxColumn no funciona así,   aunque mostrará el valor ToString si no configura el   DisplayMember, algo falla internamente cuando intenta buscar   hasta el elemento seleccionado, debe establecer DisplayMember en público   propiedad de tu clase. Peor aún, el comportamiento predeterminado si no   establecer la propiedad ValueMember es devolver el DisplayMember, hay   no hay forma de obtener el artículo real en sí. La única solución es agregar un   propiedad de su clase que se devuelve y establece esa propiedad en   El ValueMember. Por supuesto, si su artículo no es algo que pueda   para cambiar (como una de las clases de framework) tendrás que hacer cludge   juntos un objeto contenedor que contiene una referencia a su artículo.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top