Binding List <T> ke DataGridView di WinForm

91

saya ada kelas

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

dan a List<Person>yang saya tambahkan beberapa item. Daftar ini terikat pada saya 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;

Tidak ada masalah. myGridmenampilkan dua baris, tetapi ketika saya menambahkan item baru ke personsdaftar saya , myGridtidak menampilkan daftar baru yang diperbarui. Ini hanya menunjukkan dua baris yang saya tambahkan sebelumnya.

Jadi apa masalahnya?

Rebinding setiap kali bekerja dengan baik. Tapi ketika saya mengikat DataTableke grid ketika setiap kali saya membuat beberapa perubahan DataTabletidak ada kebutuhan untuk ReBind myGrid.

Bagaimana mengatasinya tanpa rebinding setiap saat?

namco
sumber

Jawaban:

188

Daftar tidak diimplementasikan IBindingListsehingga grid tidak tahu tentang item baru Anda.

Bind DataGridView Anda ke file BindingList<T>.

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

Tapi saya bahkan akan melangkah lebih jauh dan mengikat grid Anda ke 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
sumber
Dikatakan bahwa Anda juga dapat menggunakan IList dan antarmuka lainnya: msdn.microsoft.com/en-us/library/…
Pacane
4
@Pacane: Tentu Anda bisa, tetapi DataGridView perlu mengetahui apakah sumber data Anda memiliki perubahan. Onecara ist untuk menggunakan BindingList, yang akan memunculkan acara jika daftar yang mendasarinya berubah. Cara lain adalah dengan menggunakan BindingSourcedan memanggil ResetBinding () setiap kali Anda menambah / menghapus baris tetapi itu lebih banyak pekerjaan. Jika Anda ingin memberi tahu Grid tentang perubahan properti, cara termudah adalah mengimplementasikannyaINotifyPropertyChanged
Jürgen Steinblock
5
mengapa kamu menggunakan BindingList dan BindingSource karena kita bisa langsung mengikat daftar ke properti sumber data datagridview. membahas pentingnya BindingList dan BindingSource u digunakan di sini. terima kasih
Mou
5
@Mou Anda dapat mengikat datagrid ke a List<T>jika Anda mau. Tetapi jika Anda secara programatik menambahkan item ke Daftar, DataGridView tidak akan mengetahuinya karena Daftar Anda tidak mengimplikasikan IBindingList. Mengenai BindingSource: Saya sering menggunakan winforms, dan saya tidak mengikat apa pun selain BindingSource - FULLSTOP. Menambahkan lebih banyak detail terlalu banyak untuk sebuah komentar, tetapi BindingSourcememiliki begitu banyak hal yang ditawarkan tanpa kerugian apa pun. Saya akan melangkah lebih jauh dan berkataAnyone who does not use a BindingSource for binding has not fully understood windows forms databindings
Jürgen Steinblock
4
@CraigBrett Pertimbangkan BindingSourcesebagai jembatan antara sumber data dan GUI Anda. Ini memecahkan banyak masalah terkait penyatuan data. Anda ingin memuat ulang data Anda? Cukup atur bindingSource.DataSourceke koleksi baru Anda alih-alih menyatukan kembali setiap kontrol. DataSource Anda bisa nihil? Set bindingSource.DataSource = typeof(YourClass)Anda ingin memiliki kisi yang dapat diedit tetapi sumber data Anda tidak memiliki konstruktor tanpa parameter? Cukup terapkan bindingSource.AddingNewacara dan buat objek sendiri. Saya tidak pernah mengalami kerugian saat menggunakan BindingSourcetetapi banyak manfaatnya.
Jürgen Steinblock
4

Setiap kali Anda menambahkan elemen baru ke Daftar, Anda perlu mengikat kembali Grid Anda. Sesuatu seperti:

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
sumber
Saya tidak dapat melihat properti dataSource di bawah datagrid. Dapatkah Anda memberi tahu saya bagaimana cara menggunakannya?
RSB
2

Ya, itu mungkin dilakukan tanpa rebinding dengan mengimplementasikan INotifyPropertyChanged Interface.

Contoh Pretty Simple tersedia di sini,

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

Dev
sumber
1
Itu tidak cukup, jika Anda mengimplementasikan INotifyPropertyChangedDataGridView akan menampilkan semua perubahan properti yang terjadi di latar belakang, tetapi tidak akan tahu apakah Anda menambahkan / menghapus baris dari sumber Anda. Untuk tujuan ini, terdapat IBindingListantarmuka dan, untuk kenyamanan Anda, BindingList<T>implementasi yang sudah mengimplementasikannya, tetapi tidak mendukung penyortiran / pemfilteran.
Jürgen Steinblock
1
Ya, saya setuju dengan Anda. jadi saya pikir ObservableCollection <T> dapat digunakan untuk ini. Bagaimana menurut anda?
Dev
0

Setelah menambahkan item baru untuk personsditambahkan:

myGrid.DataSource = null;
myGrid.DataSource = persons;
Rafal
sumber
Saya tidak dapat melihat properti dataSource di bawah datagrid. Dapatkah Anda memberi tahu saya bagaimana cara menggunakannya?
RSB
1
Saran ini bisa menimbulkan masalah. Misalnya, Anda dapat menemukan bahwa klik pada item dalam petak bisa mendapatkan IndexOutOfRangeException karena sumber data nol pada saat itu. Akan lebih bijaksana untuk mengikat ke BindingList pada awalnya dan mengimplementasikan INotifyPropertyChanged pada objek Anda seperti yang ditunjukkan jawaban lain
steve
Apa gunanya menetapkannya nulljika Anda segera menetapkannya personsdi baris berikutnya?
Rufus L
0

Ini bukan masalah yang saya alami, tetapi jika ada yang ingin mengonversi BindingList jenis apa pun ke List dengan jenis yang sama, maka beginilah cara melakukannya:

var list = bindingList.ToDynamicList();

Selain itu, jika Anda menetapkan BindingLists tipe dinamis ke DataGridView.DataSource, pastikan Anda mendeklarasikannya terlebih dahulu sebagai IBindingList sehingga cara di atas berfungsi.

Kopfs
sumber