简体   繁体   English

C# 为什么不能设置动态创建的组合框的 selectedValue?

[英]C# Why isn't it possible to set the selectedValue of a dynamically created combobox?

I create a combobox in a class and want to set the selected value for that combobox.我在类中创建了一个组合框,并希望为该组合框设置选定的值。 But when I do that, the selectedValue stays null and when I try to set the selectedIndex I get a ArgumentOutOfRangeException.但是当我这样做时, selectedValue 保持为空,当我尝试设置 selectedIndex 时,我得到一个 ArgumentOutOfRangeException。

Code:代码:

public Control GenerateList(Question question)
{
    // Clear the local givenAnswer collection
    _givenAnswer.Clear();

    // Get a list with answer possibilities
    List<QuestionAnswer> answers = question.GetAnswerSort();

    // Get a collection of given answers
    Collection<QuestionnaireAnswer> givenAnswers = question.GetGivenAnswers();

    _givenAnswer = givenAnswers;

    ComboBox cmb = new ComboBox();
    cmb.Name = "cmb";
    cmb.DisplayMember = "Answer";
    cmb.ValueMember = "Id";
    cmb.DataSource = answers;
    cmb.Dock = DockStyle.Top;

    // Check an answer is given to the question
    if (givenAnswers != null && givenAnswers.Count > 0)
    {
        cmb.Tag = givenAnswers[0].AnswerId;
        cmb.SelectedValue = givenAnswers[0].AnswerId; // answerId = 55, but SelectedValue stays null
    }

    cmb.SelectedIndex = 1; // For testting. This will throw a ArgumentOutOfRangeException
    cmb.DropDownStyle = ComboBoxStyle.DropDownList;
    cmb.SelectedIndexChanged += new EventHandler(cmb_SelectedIndexChanged);

    return cmb;
}

I hope someone can explain to me what is happening so I can understand why it isn't working.我希望有人可以向我解释发生了什么,这样我就可以理解为什么它不起作用。

Here is a complete little program what illustrates my problem.这是一个完整的小程序,它说明了我的问题。 As you can see it doesn't set the SelectedValue, this stays null正如你所看到的,它没有设置 SelectedValue,它保持为空

namespace Dynamic_Create_Combo
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();

            GenerateControls gc = new GenerateControls();
            Control c = gc.GenerateCombo();

            this.SuspendLayout();
            this.Controls.Add(c);
            this.ResumeLayout(true);
        }
    }

    public class GenerateControls
    {
        public Control GenerateCombo()
        {
            // Create datasource
            Collection<Car> cars = new Collection<Car>();
            Car c = new Car();
            c.Id = 1;
            c.Name = "Car one";
            cars.Add(c);

            Car c1 = new Car();
            c1.Id = 2;
            c1.Name = "Car two";
            cars.Add(c1);

            Car c2 = new Car();
            c2.Id = 2;
            c2.Name = "Car three";
            cars.Add(c2);

            ComboBox cmb = new ComboBox();
            cmb.DropDownStyle = ComboBoxStyle.DropDownList;
            cmb.DataSource = cars;
            cmb.DisplayMember = "Name";
            cmb.ValueMember = "Id";

            cmb.SelectedValue = 2;

            return cmb;
        }
    }

    public class Car
    {
        private int _id;
        private string _name;

        public int Id
        {
            get { return _id; }
            set { _id = value; }
        }

        public string Name 
        {
            get { return _name; }
            set { _name = value; }
        }
    }
}

You've set the value member to be "Id" but you're trying to use "AnswerId" as the selected value.您已将值成员设置为“Id”,但您尝试使用“AnswerId”作为所选值。

Without more details, it's hard to say why setting SelectedIndex is throwing an ArgumentOutOfRangeException - perhaps the combobox is ignoring all values which don't have an "Id" property, thus giving you no values, so selecting index 1 is impossible?没有更多细节,很难说为什么设置SelectedIndex会抛出ArgumentOutOfRangeException - 也许组合框忽略了所有没有“Id”属性的值,因此没有给你任何值,所以选择索引 1 是不可能的?

EDIT: Okay, so it looks like it's only actually doing the binding when it becomes visible - or at some stage in the process.编辑:好的,所以看起来它只是在它变得可见时才真正进行绑定 - 或者在过程的某个阶段。 I've tried a few things to accelerate this, but they don't appear to help.我已经尝试了一些方法来加速这一过程,但它们似乎没有帮助。 What you can do is defer your selection:可以做的是推迟您的选择:

EventHandler visibleChangedHandler = null;
visibleChangedHandler = delegate {
    cmb.SelectedIndex = 2;
    cmb.VisibleChanged -= visibleChangedHandler; // Only do this once!
};
cmb.VisibleChanged += visibleChangedHandler;

It's an ugly workaround, but it should at least help you to get going for the moment.这是一个丑陋的解决方法,但它至少应该可以帮助您暂时开始。

This is just a guess, but maybe, the ComboBox doesn't bind the data in the DataSource until it's drawn.这只是一个猜测,但也许ComboBox在绘制之前不会绑定DataSource中的DataSource Check cmb.Items.Count in the line before the SelectedIndex = 1 .SelectedIndex = 1之前的行中检查cmb.Items.Count If it is 0 try to first add the cmb to the Form before assigning SelectedIndex .如果它是 0 尝试先将 cmb 添加到Form之前分配SelectedIndex

EDIT:编辑:

    public Control GenerateCombo() 
    { 
        // Create datasource 
        Collection<Car> cars = new Collection<Car>(); 
        Car c = new Car(); 
        c.Id = 1; 
        c.Name = "Car one"; 
        cars.Add(c); 

        Car c1 = new Car(); 
        c1.Id = 2; 
        c1.Name = "Car two"; 
        cars.Add(c1); 

        Car c2 = new Car(); 
        c2.Id = 2; 
        c2.Name = "Car three"; 
        cars.Add(c2); 

        ComboBox cmb = new ComboBox(); 
        cmb.DropDownStyle = ComboBoxStyle.DropDownList; 
        cmb.DataSource = cars; 
        cmb.DisplayMember = "Name"; 
        cmb.ValueMember = "Id"; 

        // add this: 
        EventHandler visibleChangedHandler = null; 
        visibleChangedHandler = delegate { 
            cmb.SelectedIndex = 2; 
            cmb.VisibleChanged -= visibleChangedHandler;
        }; 
        cmb.VisibleChanged += visibleChangedHandler; 

        // delete this: cmb.SelectedValue = 2; 

        return cmb; 
    } 

您需要设置 cmb.DataBindings, 可能会有所帮助。

Maybe because the combo is created during the Form_load event.可能是因为组合是在 Form_load 事件期间创建的。 Try to create your combo in the constructor and set the selection in Form_Load.尝试在构造函数中创建组合并在 Form_Load 中设置选择。

public class Form1
{


private ComboBox _comboBox1;
private Car _audi = new Car("Audi)");
private Car _porsche = new Car("Porsche");
private Car _vw = new Car("VW");

private void Form1_Load(object sender, EventArgs e)
{
    this._comboBox1.SelectedItem = _vw;

}


public Form1()
{
    Load += Form1_Load;
    // This call is required by the designer.
    InitializeComponent();

    // Add any initialization after the InitializeComponent() call.
    this._comboBox1 = new ComboBox();
    this._comboBox1.DataSource = {
        _audi,
        _porsche,
        _vw
    };
    this.Controls.Add(this._comboBox1);
}



private class Car
{

    public string Name { get; set; }

    public override string ToString()
    {
        return this.Name;

    }

    public Car(name)
    {
        this.Name = name;
    }
}

}

You may want to try SelectedItem instead of SelectedValue , and assigning the class that you want to it.您可能想尝试SelectedItem而不是SelectedValue ,并为它分配您想要的类。 For example:例如:

Car c1 = new Car();
// snip
cmb.SelectedItem = c1;

Since more than one item can have a value of 2 (as far as the ComboBox knows, anyway), I think you will have difficulty setting the value via SelectedValue .由于不止一项的值可以为 2(就ComboBox ,无论如何),我认为您将难以通过SelectedValue设置值。

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

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