简体   繁体   English

ListBox.DataSource集合与ListBox.Items之间的区别?

[英]The difference between ListBox.DataSource collection versus ListBox.Items?

I am dynamically creating a Winforms multi-select ListBox and adding it into a flowpanel control. 我正在动态创建Winforms多选ListBox并将其添加到flowpanel控件中。 I bind a datasource from an object I created and verified that the DataSource has does in fact have approximately 14 elements. 我从我创建的对象绑定数据源,并验证DataSource实际上有大约14个元素。 When I do a listBox.SetSelected(0, true) I get an System.ArgumentOutOfRangeException error thrown. 当我执行listBox.SetSelected(0, true)我收到一个System.ArgumentOutOfRangeException错误。

I have determined the problem is that while the DataSource has 14 elements, the Item collection has none (0) and is therefore throwing the exception. 我已经确定问题是,虽然DataSource有14个元素,但Item集合没有(0),因此抛出异常。 My question is why are these two different from one another, and why would I not simply do a foreach item in datasource add to the item collection? 我的问题是为什么这两者彼此不同,为什么我不简单地在数据源中添加一个foreach项添加到项集合中?

The following is the code I have so far: 以下是我到目前为止的代码:

case InsertableItemParameter.ParameterType.ListBox:
    //note: two-way bindings are not possible with multiple-select listboxes
    Label lblListBox = new Label();
    lblListBox.Text = param.DisplayText;
    ListBox listBox = new ListBox();
    listBox.DataSource = param.Values;
    listBox.DisplayMember = "Value";
    listBox.SelectionMode = SelectionMode.MultiExtended;
    listBox.Size = new System.Drawing.Size(flowPanel.Size.Width - lblListBox.Size.Width - 10, 100);
    listBox.SetSelected(0, true);   //will throw argument out of range exception here!
    listBox.SetSelected(1, true);
    flowPanel.Controls.Add(lblListBox);
    flowPanel.Controls.Add(listBox);
    flowPanel.SetFlowBreak(listBox, true);
    break;

Below is an alternative solution I attempted and worked, but again why would I use DataSource versus Items collection? 下面是我尝试和工作的替代解决方案,但为什么我会使用DataSource与Items集合?

case InsertableItemParameter.ParameterType.ListBox:
    //note: two-way bindings are not possible with multiple-select listboxes
    Label lblListBox = new Label();
    lblListBox.Text = param.DisplayText;
    ListBox listBox = new ListBox();
    //listBox.DataSource = param.Values;
    listBox.DisplayMember = "Value";
    listBox.SelectionMode = SelectionMode.MultiExtended;
    listBox.Size = new System.Drawing.Size(flowPanel.Size.Width - lblListBox.Size.Width - 10, 100);
    listBox.BeginUpdate();
    foreach (String paramater in param.Values)
    {
        listBox.Items.Add(paramater);
    }
    listBox.EndUpdate();
    listBox.SetSelected(0, true);
    listBox.SetSelected(1, true);
    flowPanel.Controls.Add(lblListBox);
    flowPanel.Controls.Add(listBox);
    flowPanel.SetFlowBreak(listBox, true);
    break;

ANSWER : Thanks for all the responses. 答案 :感谢所有回复。 The issue here is visibility and win-form rendering. 这里的问题是可见性和win-form呈现。 While the difference between DataSource and Items collections were not really addressed save a few people, the true source of my problem was resolved by calling the SetSelected() method after the form was done drawing. 虽然除了少数人之外没有真正解决DataSource和Items集合之间的差异,但是在完成绘制表单之后调用SetSelected()方法解决了我的问题的真正来源。 This causes a lot of problems in the design of my application which I have to resolve, but this is was the problem. 这导致我的应用程序设计中的许多问题,我必须解决,但这是问题所在。 See the reply I marked as the answer. 请参阅我标记为答案的回复。

Your problem probably lies elsewhere, because this code works fine: 您的问题可能在其他地方,因为此代码工作正常:

string[] ds = {"123","321"};
listBox1.DataSource = ds;
listBox1.SetSelected(1, true);
MessageBox.Show(listBox1.Items.Count.ToString()); //returns 2

Tested in a brand new C# project with a listBox1 put on the form, and the above code sitting in Form_Load . 在一个全新的C#项目中测试,其中listBox1放在表单上,​​上面的代码位于Form_Load

EDIT: I did not realize that creating a ListBox in runtime could make a difference, and especially because it matters when to set selected items. 编辑:我没有意识到在运行时创建一个ListBox可能会有所作为,特别是因为它在设置所选项时很重要。 This code works: 此代码有效:

string[] ds = { "123", "321" };
ListBox lst = new ListBox();
lst.DataSource = ds;
lst.Size = new Size(100,100);            
this.Controls.Add(lst);
//make sure to call SetSelected after adding the ListBox to the parent
lst.SetSelected(1, true);

Thanks to @Brad for pointing this out. 感谢@Brad指出这一点。 So back on the original question, replace this: 回到原来的问题,替换这个:

listBox.SetSelected(0, true);
listBox.SetSelected(1, true);
flowPanel.Controls.Add(lblListBox);
flowPanel.Controls.Add(listBox);

with this: 有了这个:

flowPanel.Controls.Add(lblListBox);
flowPanel.Controls.Add(listBox);
listBox.SetSelected(0, true);
listBox.SetSelected(1, true);

And it should work. 它应该工作。

Items From MSDN 来自MSDN的项目

This property enables you to obtain a reference to the list of items that are currently stored in the ListBox. 使用此属性可以获取对当前存储在ListBox中的项列表的引用。 With this reference, you can add items, remove items, and obtain a count of the items in the collection. 使用此引用,您可以添加项目,删除项目以及获取集合中项目的计数。 For more information about the tasks that can be performed with the item collection, see the ListBox.ObjectCollection class reference topics. 有关可以使用项集合执行的任务的更多信息,请参阅ListBox.ObjectCollection类参考主题。

Datasource From MSDN 数据源来自MSDN

An object that implements the IList or IListSource interfaces, such as a DataSet or an Array. 实现IList或IListSource接口的对象,例如DataSet或Array。 The default is null 默认值为null

I'm not an expert on this matter, but from what I read it appears that Items allows you to add/modify the contents in the list whereas Datasource retrieves and sets the content. 我不是这方面的专家,但从我看来,似乎Items允许你添加/修改列表中的内容,而Datasource检索和设置内容。

You have two options of how to get data to be available in a ListBox . 您有两种选择如何在ListBox获取数据。 You can set the DataSource or you can add the items manually via listBox.Items.Add(paramater) . 您可以设置DataSource ,也可以通过listBox.Items.Add(paramater)手动添加项目。 You cannot do both because they will step on each other hence your error 你不能两者都做,因为他们会互相踩到你的错误

...cannot add items to the Item collection when DataSource is set.

Im not sure why there are two different Collections. 我不知道为什么有两个不同的收藏品。 The Items property seems more simple. Items属性似乎更简单。

I found the reason for the exception: apparently you have to do things in a specific order, like this: 我找到了例外的原因:显然你必须按照特定的顺序做事,比如:

    //init the listbox
    var listBox1 = new ListBox();
    listBox1.Location = new System.Drawing.Point(122, 61);
    listBox1.Size = new System.Drawing.Size(205, 147);
    listBox1.SelectionMode = SelectionMode.MultiExtended;
    Controls.Add(listBox1); //<-- point of interest

    //then set the DataSource
    listBox1.DataSource = lst;
    listBox1.DisplayMember = "Name";
    listBox1.ValueMember = "Age";

    //then set the selected values
    listBox1.SetSelected(0, true);
    listBox1.SetSelected(1, true);

My Test class look like this: 我的Test类看起来像这样:

public class Test
{
    private static Random r = new Random();
    public Test (string name)
    {
        Name = name;
        Age = r.Next(16, 45);
    }

    public string Name { get; set; }

    public int Age{ get; set; }
}

And lst is declared like this: 并且lst声明如下:

    var lst = new List<Test>()
                  {
                      new Test("jens"),
                      new Test("Tom"),
                      new Test("John"),
                      new Test("Don"),
                      new Test("Jenny"),
                  };

The Items collection is populated from the DataSource only when the Control is visible. 仅当Control可见时,才会从DataSource填充Items集合。 since you create your control dynamically, it is not added to the parent control and therefore not visible. 由于您动态创建控件,因此它不会添加到父控件中,因此不可见。 Therefore you first need to have a Control that is visible on the screen. 因此,您首先需要一个在屏幕上可见的控件。 In your code you set DataSource and then set the selected items before your Control is visible on the FlowChart since it isn't added to the Parent control. 在代码中设置DataSource,然后在FlowChart上显示Control之前设置所选项,因为它未添加到Parent控件。 You should change the sequence of the statements. 您应该更改语句的顺序。 You should add the listBox to the FlowPanel which will populate Items collection from the DataSource upon which you can execute SetSelected() method. 您应该将listBox添加到FlowPanel ,它将从DataSource填充Items集合,您可以在其上执行SetSelected()方法。 Try this and note the changed order of the execution of your initial code: 试试这个并记下初始代码执行的更改顺序:

ListBox listBox = new ListBox();
listBox.DataSource = param.Values;
listBox.DisplayMember = "Value";
listBox.SelectionMode = SelectionMode.MultiExtended;
listBox.Size = new System.Drawing.Size(flowPanel.Size.Width - lblListBox.Size.Width - 10, 100);
flowPanel.Controls.Add(lblListBox);
flowPanel.Controls.Add(listBox); //notice that you first add the listBox to the flowChart
listBox.SetSelected(0, true);   //and then you have items in the Items collection which you can select
listBox.SetSelected(1, true);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM