Lista de vinculação <T> para DataGridView no WinForm

90

Eu tenho uma aula

class Person{
      public string Name {get; set;}
      public string Surname {get; set;}
}

e um List<Person>ao qual adiciono alguns itens. A lista está vinculada ao meu DataGridView.

List<Person> persons = new List<Person>();
persons.Add(new Person(){Name="Joe", Surname="Black"});
persons.Add(new Person(){Name="Misha", Surname="Kozlov"});
myGrid.DataSource = persons;

Não tem problema. myGridexibe duas linhas, mas quando adiciono novos itens à minha personslista, myGridnão mostra a nova lista atualizada. Mostra apenas as duas linhas que adicionei antes.

Então qual é o problema?

Ligar sempre funciona bem. Mas quando eu vinculo um DataTableà grade, toda vez que faço algumas alterações DataTable, não há necessidade de religar myGrid.

Como resolver isso sem religar todas as vezes?

namco
fonte

Respostas:

186

A lista não implementa, IBindingListportanto a grade não sabe sobre seus novos itens.

Vincule seu DataGridView a um BindingList<T>.

var list = new BindingList<Person>(persons);
myGrid.DataSource = list;

Mas eu iria ainda mais longe e vincularia sua grade a um BindingSource

var list = new List<Person>()
{
    new Person { Name = "Joe", },
    new Person { Name = "Misha", },
};
var bindingList = new BindingList<Person>(list);
var source = new BindingSource(bindingList, null);
grid.DataSource = source;
Jürgen Steinblock
fonte
Diz que você também pode usar IList e outras interfaces: msdn.microsoft.com/en-us/library/…
Pacane
4
@Pacane: Claro que pode, mas o DataGridView precisa saber se sua fonte de dados tem alguma alteração. OneÉ uma maneira de usar um BindingList, que levantará um evento se a lista subjacente mudar. Outra maneira é usar um BindingSourcee chamar ResetBinding () toda vez que você adicionar / deletar uma linha, mas isso dá mais trabalho. Caso queira informar a Rede sobre as mudanças nas propriedades a maneira mais fácil é implementarINotifyPropertyChanged
Jürgen Steinblock
5
por que você usou BindingList e BindingSource porque podemos vincular diretamente a lista à propriedade da fonte de dados do datagridview. discuta a importância de BindingList e BindingSource u usados ​​aqui. obrigado
Mou
5
@Mou Você pode vincular um DataGrid a um, List<T>se desejar. Mas se você adicionar itens de forma programática ao List DataGridView não saberá disso porque List não implica IBindingList. Em relação a BindingSource: Eu uso muito winforms e não me vinculo a nada além de BindingSource - FULLSTOP. Adicionar mais detalhes é demais para um comentário, mas BindingSourcetem muito a oferecer sem quaisquer desvantagens. Eu iria tão longe e diriaAnyone who does not use a BindingSource for binding has not fully understood windows forms databindings
Jürgen Steinblock
4
@CraigBrett Considere BindingSourcecomo uma ponte entre sua fonte de dados e sua GUI. Ele resolve muitos problemas relacionados à ligação de dados. Você quer recarregar seus dados? Basta definir bindingSource.DataSourcesua nova coleção em vez de religar todos os controles. Seu DataSource pode ser nulo? Conjunto bindingSource.DataSource = typeof(YourClass)Você deseja ter uma grade editável, mas sua fonte de dados não tem um construtor sem parâmetros? Basta implementar o bindingSource.AddingNewevento e criar o objeto você mesmo. Nunca experimentei uma desvantagem durante o uso, BindingSourcemas muitos benefícios.
Jürgen Steinblock
4

Cada vez que você adiciona um novo elemento à lista, você precisa religar sua grade. Algo como:

List<Person> persons = new List<Person>();
persons.Add(new Person() { Name = "Joe", Surname = "Black" });
persons.Add(new Person() { Name = "Misha", Surname = "Kozlov" });
dataGridView1.DataSource = persons;

// added a new item
persons.Add(new Person() { Name = "John", Surname = "Doe" });
// bind to the updated source
dataGridView1.DataSource = persons;
Dimitar Dimitrov
fonte
Não consigo ver a propriedade dataSource em datagrid. Você pode me dizer como faço para usá-la?
RSB
2

Sim, é possível fazer com nossa religação implementando a interface INotifyPropertyChanged.

Um exemplo muito simples está disponível aqui,

http://msdn.microsoft.com/en-us/library/system.componentmodel.inotifypropertychanged.aspx

Dev
fonte
1
Isso não é suficiente, se você implementar INotifyPropertyChangedo DataGridView irá mostrar todas as alterações de propriedade que acontecem em segundo plano, mas não saberá se você adicionar / excluir uma linha de sua fonte. Para isso existe uma IBindingListinterface e, para sua comodidade, uma implementação BindingList<T>que já a implementa, mas não suporta ordenação / filtragem.
Jürgen Steinblock
1
Sim, eu concordaria com você. então acho que ObservableCollection <T> pode ser usado para isso. O que você acha?
Dev
0

Depois de adicionar um novo item para personsadicionar:

myGrid.DataSource = null;
myGrid.DataSource = persons;
Rafal
fonte
Não consigo ver a propriedade dataSource em datagrid. Você pode me dizer como faço para usá-la?
RSB
1
Esta sugestão pode causar problemas. Por exemplo, você pode descobrir que um clique em um item na grade pode obter uma IndexOutOfRangeException, já que a fonte de dados é nula naquele ponto. Seria mais sensato vincular a um BindingList inicialmente e implementar INotifyPropertyChanged em seu objeto como outras respostas indicam
steve
Qual é o objetivo de atribuí-lo nullse você atribuí-lo imediatamente personsna próxima linha?
Rufus L
0

Este não é exatamente o problema que eu tive, mas se alguém está procurando converter um BindingList de qualquer tipo em List do mesmo tipo, então é feito assim:

var list = bindingList.ToDynamicList();

Além disso, se você estiver atribuindo BindingLists de tipos dinâmicos a um DataGridView.DataSource, certifique-se de declará-lo primeiro como IBindingList para que o acima funcione.

Kopfs
fonte