ListBox.DataSource出现奇怪的问题

9

我正在编写一个Windows应用程序,使用Listbox控件。我正在使用Visual Studio C# 2008 Express Edition进行开发。

我有一个数据对象,它看起来像这样

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

我在表单上有一个ListBox控件,还有一个名为"MyRootObject"的属性,该属性显然保存了一个RootObject对象。当控件初始化时,我设置:

_listBox.DataSource = MyRootObject.MySubObjects;

现在,当表单加载时,我调试并查看到DataSource被正确设置。但是没有显示任何内容。我重写了SubObject的ToString()方法,甚至都没有被调用。我尝试将_listBox.DisplayMember设置为SubObject的属性,只是为了查看是否存在问题,但仍然没有任何反应。我在设置DataSource后尝试调用_listBox.Update()和_listBox.Refresh(),但仍然没有作用。DataSource有所有数据...只是拒绝显示它。
因此,在调试时,我想知道WTF,所以我决定只做
_listBox.DataSource = new List<SubObject>{ new SubObject(), new SubObject() };

果然,这起作用了,我在列表框中看到了两件事情。

然后,我非常好奇,决定尝试复制对象列表并将其放入列表框中,像这样:

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

这个方法有效!但目前它只是我的问题的一种解决方法...非常让人烦恼。有没有人知道为什么我需要基本上像这样复制对象列表才能使它工作,而不是只设置 _listBox.DataSource = MyRootObject.MySubObjects;?同样,在设置后,DataSource 两种方式都具有正确的数据...只有在复制数据时,它才会显示出来,而当没有复制时,则不会显示。

8个回答

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

我知道这很糟糕,但这个方法是有效的。(最初的答案在这里找到:这里

1

据我所知,每当您想将一个集合设置为

[ComboBox,ListBox].DataSource

你需要设置 DisplayMember 和 ValueMember。DisplayMember 和 ValueMember 填充的是分配给 listbox/combobox 的集合中的类的属性名称。例如:

//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;

root.MySubObjects 返回 SubObject 列表,而 SubObject 必须具有名为 DisplayProperty 和 ValueProperty 的属性,例如:

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

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

1
设置 DisplayMember 和 ValueMember 是常见的,但是可选的;如果您不配置 DisplayMember,则控件会调用对象的 ToString() 方法;如果您不设置 ValueMember,则控件将返回整个对象作为值。 - Bevan

1

就我个人的理解,这是因为 ListBox.DataSource 属性必须包含实现了 IList 接口的内容。而你的泛型 List<SubObject> 并没有实现 IList 接口;它实现了 IList<T>(在 System.Collections.Generic 命名空间中)。另一方面,Array 对象继承自 IList,所以通过这种对象传递数据是可行的。

你可以尝试从你的 List<SubObject> 对象中提取一个实现了 IList 接口的 Enumerator,然后将其插入。如果能够正常工作,那么我描述的问题就是你的问题。如果不能正常工作,那么我说的可能就不准确了。

如果确实是这个问题,我对于插入一个不支持的对象却没有抛出异常感到惊讶。


我也遇到了同样的问题,而这个页面说List<T>实现了IList和IList<T>:https://social.msdn.microsoft.com/Forums/vstudio/en-US/a58e4f37-4abd-4eff-820e-33d09a7a432d/net-classes-that-implement-ilist?forum=netfxbcl - Peter Howe

0

你可以尝试一下

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

BindingList 实现了比 List 更多的接口,这些接口在数据绑定中是必不可少的。


0
我认为在分配数据源后需要调用_listbox.DataBind()。 然而,我以前从未使用过属性作为数据源,我只使用过方法。你尝试将你的属性更改为方法来查看是否存在问题了吗?

2
我可能错了,但我认为这仅适用于ASP.NET。我认为OP可能正在使用Winforms。 - Scott Whitlock
对不起,我没有注意到。你可能是正确的。感谢澄清。 :-) - René

0

对于这种问题,我有一个特殊的规则,总是在浪费整整一天时间之前尝试记住它(相信我,我已经花了很多天时间)。这个规则是:当系统行为非常奇怪时,根本原因一定非常愚蠢。作为聪明的程序员,我们倾向于寻找奇怪的原因或框架代码中的错误来解释我们的问题。有时候答案是我们匆忙之间犯了一个粗心的错误,而我们还没有发现。

引用福尔摩斯的话,“当你排除了不可能的事情,那么无论多么不可思议,剩下的必定是真相”。在这种情况下,不可思议的真相是MyRoot对象的MySubObjects属性为空。


0
我认为在将数据源分配给列表框后,您需要调用Bind方法,例如_listBox.DataSource.bind(),这样您的列表框就会消失。

0

你可以尝试使用BindingSource(http://msdn.microsoft.com/en-us/library/system.windows.forms.bindingsource.aspx

在ListBox和你的集合之间添加BindingSource。BindingSource可以处理许多东西,并包括Suspend/ResumeBinding属性,在更新列表时非常有用。

你也可以尝试使用WPF,因为其数据绑定远远优于WinForms :) 但也许在你的情况下不可能。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接