2009-03-23 30 views
9

Tôi đang viết một ứng dụng Windows và sử dụng một điều khiển Listbox. Tôi đang phát triển với Visual Studio C# 2008 Express Edition.Vấn đề kỳ lạ với ListBox.DataSource

Tôi đã có một đối tượng dữ liệu mà trông giống như sau

public class RootObject 
{ 
    public List<SubObject> MySubObjects{ get; set;} 
} 

Tôi đã có một ListBox vào mẫu của tôi, và cũng là một tài sản "MyRootObject" mà, rõ ràng, nắm giữ một RootObject. Khi điều khiển được khởi tạo, tôi đã đặt:

_listBox.DataSource = MyRootObject.MySubObjects; 

Bây giờ, khi biểu mẫu tải, tôi gỡ lỗi và thấy rằng DataSource đang được đặt chính xác. Nhưng không có gì được hiển thị. Tôi đã ghi đè lên phương thức ToString() của SubObject và nó thậm chí không được gọi. Tôi đã thử đặt _listBox.DisplayMember thành thuộc tính của SubObject chỉ để xem có vấn đề gì ở đó không, nhưng vẫn không có gì. Tôi đã thử gọi _listBox.Update() và _listBox.Refresh() sau khi thiết lập DataSource, nhưng vẫn không có tình yêu. DataSource có tất cả dữ liệu ... nó chỉ từ chối hiển thị nó.

Vì vậy, trong khi gỡ lỗi, tôi tự hỏi WTF và tôi quyết định chỉ làm đủ

_listBox.DataSource = new List<SubObject>{ new SubObject(), new SubObject() }; 

Chắc chắn, điều này làm việc, và tôi thấy hai điều được liệt kê trong hộp danh sách của tôi.

Vì vậy, sau đó, thực sự tò mò, tôi quyết định thử sao chép danh sách các đối tượng và đưa rằng trong hộp danh sách, như vậy:

_listBox.DataSource = MyRootObject.MySubObjects.ToArray(); 

này hoạt động! Và đó là một giải pháp cho vấn đề của tôi bây giờ ... nhưng một điều rất khó chịu. Có ai biết tại sao tôi cần phải về cơ bản sao chép danh sách các đối tượng như thế này để có được nó để làm việc, hơn là chỉ cần thiết lập _listBox.DataSource = MyRootObject.MySubObjects; ? Một lần nữa, DataSource có tất cả các dữ liệu đúng theo cách sau khi thiết lập nó ... nó chỉ là khi nó được sao chép dữ liệu, nó thực sự hiển thị, và khi nó không, nó không được hiển thị.

Trả lời

1

Tắt đầu của tôi, điều này là do thuộc tính ListBox.DataSource phải chứa thứ gì đó triển khai giao diện IList. Số chung của bạn List<SubObject> không thực hiện IList; nó thực hiện IList<T> (trong không gian tên System.Collections.Generic). Mặt khác, các đối tượng Array làm kế thừa từ IList, do đó việc truyền dữ liệu qua loại đối tượng đó hoạt động.

Bạn có thể thử kéo Enumerator (cũng thực hiện IList) ra khỏi đối tượng List<SubObject> và cắm vào. Nếu nó hoạt động thì vấn đề tôi đã mô tả là sự cố của bạn. Nếu không, thì tôi đang nói chuyện với chiếc mũ của mình.

Nếu điều này thực sự là vấn đề, tôi ngạc nhiên rằng xô đẩy trong một đối tượng không được hỗ trợ không ném ngoại lệ.

+0

Tôi có vấn đề này giống nhau, và trang này nói rằng Danh sách KHÔNG thực hiện IList cũng như IList : https://social.msdn.microsoft.com/Forums/vstudio/en- US/a58e4f37-4abd-4eff-820e-33d09a7a432d/net-lớp-mà-thực hiện-ilist? Diễn đàn = netfxbcl –

0

Tôi nghĩ rằng bạn phải gọi phương thức Bind sau gán vào nguồn dữ liệu hộp danh sách cái gì đó như _listBox.DataSource.bind() và bạn sẽ có listbox của bạn biến mất

0

bạn có thể thử và sử dụng một BindingSource (http://msdn.microsoft.com/en-us/library/system.windows.forms.bindingsource.aspx)

giữa hộp danh sách và bộ sưu tập của bạn.Bindingsources xử lý một loạt các công cụ và cũng bao gồm các tính năng Suspend/ResumeBinding có thể hữu ích khi cập nhật danh sách

bạn cũng có thể thử wpf như dữ liệu của nó cao hơn nhiều so với winforms :) nhưng có thể là không thể trường hợp

0

Tôi tin rằng bạn cần gọi _listbox.DataBind(); sau khi gán nguồn dữ liệu. Tuy nhiên, trước đây tôi chưa từng sử dụng thuộc tính làm nguồn dữ liệu, tôi chỉ sử dụng các phương thức. Bạn đã thử thay đổi thuộc tính của mình thành một phương pháp để xem đó có phải là vấn đề không?

+2

Tôi có thể sai nhưng tôi tin rằng đó là chỉ áp dụng trong ASP.NET. Tôi nghĩ rằng OP có lẽ đang sử dụng Winforms. –

+0

Tôi xin lỗi, tôi không nhận thấy điều đó. Có lẽ bạn đã đúng. Cảm ơn bạn đã làm rõ. :-) –

1

cho đến nay mà tôi biết, bất cứ khi nào bạn muốn thiết lập một bộ sưu tập với một

[ComboBox,ListBox].DataSource 

bạn phải thiết lập các DisplayMember và ValueMember. DisplayMember và ValueMember được lấp đầy với tên thuộc tính của Class trong bộ sưu tập được gán cho listbox/combobox. Ví dụ

//Populate the data 
RootObject root = new RootObject(); 
root.MySubObjects.Add(new SubObject("1", "data 1")); 
root.MySubObjects.Add(new SubObject("2", "data 2")); 

//Assign data to the data source 
_listBox.DisplayMember = "DisplayProperty"; 
_listBox.ValueMember = "ValueProperty"; 
_listBox.DataSource = root.MySubObjects; 

root2yububObjects returns

public class RootObject 
{ 
    public List<SubObject> MySubObjects { get; set; } 
} 

public class SubObject 
{ 
    public string ValueProperty { get; set; } 
    public string DisplayProperty { get; set; } 
} 
+1

Cài đặt DisplayMember và ValueMember là bình thường nhưng không bắt buộc; nếu bạn không cấu hình DisplayMember, điều khiển sẽ gọi ToString() trên đối tượng; và nếu bạn không đặt ValueMember, điều khiển sẽ trả về toàn bộ đối tượng cho giá trị. – Bevan

0

Bạn có thể thử

_listBox.DataSource = new BindingList<SubObject> (MyRootObject.MySubObjects); 

để thay thế. BindingList thực hiện một số giao diện hơn Danh sách, đó là điều cần thiết cho DataBinding.

0

Tôi có một quy tắc đặc biệt cho những vấn đề như thế này mà tôi luôn cố gắng nhớ trước khi lãng phí cả ngày rèn luyện nó (tin tôi đi, tôi đã dành nhiều ngày rèn!). Quy tắc là: khi hành vi hệ thống thực sự lạ, nguyên nhân cơ bản phải rất ngu xuẩn. Là người lập trình thông minh, chúng ta có khuynh hướng tìm kiếm các nguyên nhân bí mật hoặc lỗi trong mã khung công tác để giải thích các vấn đề của chúng ta. Đôi khi câu trả lời là chúng tôi đang vội vàng và tạo ra một sai lầm bất cẩn mà chúng tôi chưa gặp phải.

Để trích dẫn Sherlock Holmes, "khi bạn đã loại bỏ điều không thể, thì bất cứ điều gì còn lại, bất kể không thể xảy ra, phải là sự thật". Trong trường hợp này, sự thật không thể xảy ra là thuộc tính MySubObjects của đối tượng MyRoot là null.

5
((CurrencyManager)_listBox.BindingContext[_listBox.DataSource]).Refresh(); 

Sux0r Tôi biết, nhưng điều này có hiệu quả. (câu trả lời ban đầu tìm thấy here)

Các vấn đề liên quan