7

我正在动态创建一个 Winforms 多选 ListBox 并将其添加到流程面板控件中。我从我创建的对象绑定数据源,并验证 DataSource 实际上有大约 14 个元素。当我这样做时,我会抛出listBox.SetSelected(0, true)一个错误。System.ArgumentOutOfRangeException

我已经确定问题是,虽然 DataSource 有 14 个元素,但 Item 集合没有 (0),因此引发了异常。我的问题是为什么这两个彼此不同,为什么我不简单地将数据源中的 foreach 项目添加到项目集合中?

以下是我到目前为止的代码:

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;

下面是我尝试和工作的另一种解决方案,但为什么我还要使用 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;

回答: 感谢所有的回复。这里的问题是可见性和 win-form 渲染。虽然 DataSource 和 Items 集合之间的差异并没有真正解决(除了少数人),但我的问题的真正根源是通过SetSelected()在表单完成绘制后调用该方法来解决的。这在我的应用程序设计中引起了很多我必须解决的问题,但这就是问题所在。请参阅我标记为答案的回复。

4

5 回答 5

4

您的问题可能出在其他地方,因为此代码可以正常工作:

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

在一个全新的 C# 项目中进行了测试,listBox1表单上有一个 put,上面的代码位于Form_Load.

编辑:我没有意识到ListBox在运行时创建 a 可能会有所作为,尤其是因为何时设置选定项目很重要。此代码有效:

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

感谢@Brad 指出这一点。所以回到原来的问题,替换这个:

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

有了这个:

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

它应该工作。

于 2013-03-04T18:51:40.290 回答
2

您有两种选择如何让数据在ListBox. 您可以设置DataSource或您可以通过手动添加项目listBox.Items.Add(paramater)。你不能两者都做,因为它们会互相踩踏,因此你的错误

...cannot add items to the Item collection when DataSource is set.
于 2013-03-04T18:50:33.100 回答
1

来自MSDN 的项目

此属性使您能够获取对当前存储在 ListBox 中的项目列表的引用。使用此引用,您可以添加项目、删除项目并获取集合中项目的计数。有关可以使用项目集合执行的任务的详细信息,请参阅 ListBox.ObjectCollection 类参考主题。

来自MSDN的数据源

实现 IList 或 IListSource 接口的对象,例如 DataSet 或 Array。默认为空

我不是这方面的专家,但从我读到的内容看来,Items 允许您添加/修改列表中的内容,而 Datasource 检索和设置内容。

于 2013-03-04T18:43:58.757 回答
1

我不确定为什么有两个不同的集合。该Items属性似乎更简单。

我找到了异常的原因:显然你必须按照特定的顺序做事,像这样:

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

我的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; }
}

lst声明如下:

    var lst = new List<Test>()
                  {
                      new Test("jens"),
                      new Test("Tom"),
                      new Test("John"),
                      new Test("Don"),
                      new Test("Jenny"),
                  };
于 2013-03-04T18:53:50.747 回答
1

仅当控件可见时,才会从 DataSource 填充 Items 集合。由于您动态创建控件,因此它不会添加到父控件,因此不可见。因此,您首先需要有一个在屏幕上可见的控件。在您的代码中,您设置 DataSource ,然后在您Control可见之前设置所选项目,FlowChart因为它没有添加到Parent控件中。您应该更改语句的顺序。您应该添加listBoxFlowPanel将填充 Items 集合DataSource,您可以在其上执行SetSelected()方法。试试这个并注意初始代码执行的更改顺序:

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);
于 2013-03-04T18:55:28.963 回答