Danh sách ràng buộc <T> với DataGridView trong WinForm


91

Tôi có một lớp học

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

và một List<Person>mà tôi thêm một số mục. Danh sách được ràng buộc với của tôi 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;

Không có vấn đề gì cả. myGridhiển thị hai hàng, nhưng khi tôi thêm các mục mới vào personsdanh sách của mình , myGridkhông hiển thị danh sách cập nhật mới. Nó chỉ hiển thị hai hàng mà tôi đã thêm trước đó.

Vì vậy, vấn đề là gì?

Rebinding mọi lúc đều hoạt động tốt. Nhưng khi tôi liên kết a DataTablevào lưới khi mỗi khi tôi thực hiện một số thay đổi đối với DataTablekhông cần phải Tìm lại myGrid.

Làm thế nào để giải quyết nó mà không phải đóng lại mỗi lần?

Câu trả lời:


187

Danh sách không triển khai IBindingListnên lưới không biết về các mục mới của bạn.

Liên kết DataGridView của bạn với một BindingList<T>thay thế.

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

Nhưng tôi thậm chí sẽ đi xa hơn và liên kết lưới của bạn với 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;

Nó nói rằng bạn có thể sử dụng IList và các giao diện khác: msdn.microsoft.com/en-us/library/…
Pacane

4
@Pacane: Chắc chắn bạn có thể làm được, nhưng DataGridView cần biết liệu nguồn dữ liệu của bạn có bất kỳ thay đổi nào hay không. Onecách là sử dụng BindingList, danh sách này sẽ Tăng sự kiện nếu danh sách cơ bản thay đổi. Một cách khác là sử dụng a BindingSourcevà gọi ResetBinding () mỗi khi bạn thêm / xóa Hàng nhưng cách đó sẽ hoạt động nhiều hơn. Nếu bạn muốn thông báo Lưới về những thay đổi sở hữu cách dễ nhất là để thực hiệnINotifyPropertyChanged
Jürgen Steinblock

5
tại sao bạn lại sử dụng BindingList và BindingSource bởi vì chúng tôi có thể liên kết trực tiếp danh sách với thuộc tính nguồn dữ liệu datagridview. thảo luận về tầm quan trọng của BindingList và BindingSource u được sử dụng ở đây. cảm ơn
Mou

5
@Mou Bạn có thể liên kết DataGrid với a List<T>nếu bạn muốn. Nhưng nếu bạn thêm các mục vào Danh sách DataGridView theo chương trình sẽ không biết về nó vì Danh sách của bạn không tích hợp IBindingList. Về BindingSource: Tôi sử dụng winforms rất nhiều và tôi không ràng buộc với bất kỳ thứ gì khác ngoài BindingSource - FULLSTOP. Để thêm chi tiết là quá nhiều cho một bình luận, nhưng BindingSourcecó quá nhiều thứ để cung cấp mà không có bất kỳ nhược điểm nào. Tôi sẽ đi rất xa và nóiAnyone who does not use a BindingSource for binding has not fully understood windows forms databindings
Jürgen Steinblock

4
@CraigBrett Coi BindingSourcenhư là cầu nối giữa nguồn dữ liệu và GUI của bạn. Nó giải quyết nhiều vấn đề liên quan đến databinding. Bạn muốn tải lại dữ liệu của mình? Chỉ cần đặt thành bindingSource.DataSourcebộ sưu tập mới của bạn thay vì đóng lại mọi điều khiển. DataSource của bạn có thể trống? Đặt bindingSource.DataSource = typeof(YourClass)Bạn muốn có một lưới có thể chỉnh sửa nhưng nguồn dữ liệu của bạn không có hàm tạo không tham số? Chỉ cần triển khai bindingSource.AddingNewsự kiện và tự tạo đối tượng. Tôi chưa bao giờ gặp phải nhược điểm khi sử dụng BindingSourcenhưng rất nhiều lợi ích.
Jürgen Steinblock

4

Mỗi khi bạn thêm một phần tử mới vào Danh sách, bạn cần phải liên kết lại Grid của mình. Cái gì đó như:

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;

Tôi không thể nhìn thấy thuộc tính dataSource trong datagrid. Bạn có thể cho tôi biết cách sử dụng nó không?
RSB

2

Có, bạn hoàn toàn có thể thực hiện việc loại bỏ ràng buộc bằng cách triển khai Giao diện INotifyPropertyChanged.

Ví dụ khá đơn giản có sẵn ở đây,

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


1
Điều đó là chưa đủ, nếu bạn triển khai INotifyPropertyChangedDataGridView sẽ hiển thị tất cả các thay đổi thuộc tính xảy ra trong nền, nhưng nó sẽ không biết nếu bạn thêm / xóa một hàng khỏi nguồn của mình. Vì mục đích này, có một IBindingListgiao diện và, vì sự thuận tiện của bạn, một giao diện BindingList<T>đã triển khai nó, nhưng không hỗ trợ sắp xếp / lọc.
Jürgen Steinblock

1
Vâng, tôi sẽ đồng ý với bạn. vì vậy tôi nghĩ ObservableCollection <T> có thể được sử dụng cho việc này. Bạn nghĩ sao?
Dev

0

Sau khi thêm mục mới để personsthêm:

myGrid.DataSource = null;
myGrid.DataSource = persons;

Tôi không thể nhìn thấy thuộc tính dataSource trong datagrid. Bạn có thể cho tôi biết cách sử dụng nó không?
RSB

1
Đề xuất này có thể gây ra vấn đề. Ví dụ: bạn có thể thấy rằng một cú nhấp chuột vào một mục trong lưới có thể nhận được một IndexOutOfRangeException vì nguồn dữ liệu là rỗng tại thời điểm đó. Sẽ là khôn ngoan hơn nếu ban đầu liên kết với BindingList và triển khai INotifyPropertyChanged trên đối tượng của bạn như các câu trả lời khác chỉ ra
steve

Điểm của việc gán nó cho nullnếu bạn ngay lập tức gán nó cho personsdòng tiếp theo?
Rufus L

0

Đây không phải là vấn đề chính xác mà tôi gặp phải, nhưng nếu bất kỳ ai đang tìm cách chuyển đổi BindingList thuộc bất kỳ loại nào thành Danh sách cùng loại, thì đây là cách thực hiện:

var list = bindingList.ToDynamicList();

Ngoài ra, nếu bạn đang gán BindingLists của các loại động cho DataGridView.DataSource, thì hãy đảm bảo rằng bạn khai báo nó trước là IBindingList để các thao tác trên hoạt động.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.