Como obrigado a DataGridViewComboBoxColumn a um objeto?
-
08-07-2019 - |
Pergunta
Eu estou tentando ligado um DataGridViewComboBoxColumn
para uma instância de Foo, mas quando eu definir um valor no grid eu tenho um ArgumentException
me dizendo que eu não posso converter de String para 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
Estou faltando alguma coisa? é possível vincular a um objeto complexo?
UPDATE:
Eu implementou um TypeConverter e overrided CanConvertFrom, CanConvertTo, ConvertTo, ConvertFrom. Agora eu estou recebendo
FormatException: O valor DataGridViewComboBoxCell não é válido
Todas as idéias?
Solução
Está faltando uma possível peça.
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;
UPDATE:
Na verdade, depois de ler a sua pergunta novamente, eu acho que você está enfrentando esse bug observou. Infelizmente, não há maneira de fazê-lo retornar o objeto vinculado sem usar um TypeDescriptor custom / TypeConverter / BindingSource.
Resposta para a ligação a um objeto complexo. Não por padrão. Eu escrevi bastante uma agradável para o meu projeto atual. Isso envolve a criação de um TypeDescriptor custom / TypeConverter / BindingSource que retorna todas as propriedades aninhadas. Outro 'bug', você não pode usar '' para um separador de membro, I teve de recorrer à ':' em vez
.Outras dicas
o DataGridViewComboBoxColumn deve sempre ter todos os valores possíveis na lista de Itens combobox ou ele vai jogar. "FormatException: O valor DataGridViewComboBoxCell não é válido"
Se você está tentando voltar valores escolhidos a partir de uma coluna combobox, você pode manipular o evento DataGridView CellParsing, e obter o item selecionado da DataGridView.EditingControl porque isso será definido para controle de edição da coluna editada. Aqui é um exemple:
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;
}
}
Você também pode personalizar a forma como os objetos são mostrados em cada célula por manipulação da célula formatação do evento, aqui é um código que toString exibição para qualquer objeto ou interface.
private void dataGridView1_CellFormatting(object sender,
DataGridViewCellFormattingEventArgs e) {
if (e.Value != null) {
e.Value = e.Value.ToString();
e.FormattingApplied = true;
}
}
lida com esse dois eventos deve ser suficiente para mostrar e editar dados dentro de qualquer objeto bussiness e seu easer, em seguida, conversores de tipo de escrita. Para este trabalho fixado de DataGridView e você combobox coluna a seguir:
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 DisplayMember ou necessidade ValueMember propriedade a ser definida, apenas certifique-se a sua lista de fonte de dados lista tem todos os valores possíveis para Foo.
Hope sua ajuda.
Na verdade, você pode usar um tipo complexo no DataGridViewComboBoxColumn
.
Por exemplo:
DataGridViewComboBoxColumn.DataPropertyName = "ValueMode";
DataGridViewComboBoxColumn.DisplayMember = "Label";
DataGridViewComboBoxColumn.ValueMember = "Self"; *
DataGridViewComboBoxColumn.ValueType = typeof(ValueModeItem);
Self
é:
public ValueModeItem Self
{
get
{
return this;
}
}
Muito importante - a necessidade de substituir 'é igual a' método de um tipo complexo. No meu caso:
public override bool Equals(object obj)
{
if (obj is ValueModeItem && obj != null)
{
if (...)
return true;
}
return false;
}
Eu estava constantely bater o mesmo problema até que eu viúva que você não pode definir o DisplayMember
do DataGridViewComboBoxCell
sem definir o ValueMember
também.
Da mesma forma, a definição da ValueMember
e não o DisplayMember
é uma falha muito, você tem que definir nenhum ou ambos.
Seu modelo é Foo, e você certamente deseja que o valor do ComboBox ser o item em si. Para fazer isso, a maneira mais simples é também criar uma propriedade em sua foo, voltando-se.
public class Foo
{
...
public Foo This { get {return this; } }
}
ligações torna-se então:
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";
Isso deve funcionar, eo valor da célula deve ser do tipo Foo como esperado.
Uma referência interessante: Problemas com o DataGridViewComboBoxColumn
No entanto, o DataGridViewComboBoxColumn não funciona assim, embora ele irá exibir o valor ToString se você não definir o DisplayMember, algo dá internamente errado quando se tenta olhar o SelectedItem, você tem que definir DisplayMember a um público propriedade de sua classe. Pior ainda, o comportamento padrão se você não faz definir a propriedade ValueMember é devolver o DisplayMember, há nenhuma maneira de obter item real em si. A única solução é adicionar um propriedade para sua classe que retorna-se e definir essa propriedade para o ValueMember. Claro, se o item não é algo que você é capaz a alteração (como uma das classes do framework) você terá que cludge juntos um objeto recipiente que contém uma referência ao seu item.