繁体   English   中英

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

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

我在类中创建了一个组合框,并希望为该组合框设置选定的值。 但是当我这样做时, selectedValue 保持为空,当我尝试设置 selectedIndex 时,我得到一个 ArgumentOutOfRangeException。

代码:

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

我希望有人可以向我解释发生了什么,这样我就可以理解为什么它不起作用。

这是一个完整的小程序,它说明了我的问题。 正如你所看到的,它没有设置 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; }
        }
    }
}

您已将值成员设置为“Id”,但您尝试使用“AnswerId”作为所选值。

没有更多细节,很难说为什么设置SelectedIndex会抛出ArgumentOutOfRangeException - 也许组合框忽略了所有没有“Id”属性的值,因此没有给你任何值,所以选择索引 1 是不可能的?

编辑:好的,所以看起来它只是在它变得可见时才真正进行绑定 - 或者在过程的某个阶段。 我已经尝试了一些方法来加速这一过程,但它们似乎没有帮助。 可以做的是推迟您的选择:

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

这是一个丑陋的解决方法,但它至少应该可以帮助您暂时开始。

这只是一个猜测,但也许ComboBox在绘制之前不会绑定DataSource中的DataSource SelectedIndex = 1之前的行中检查cmb.Items.Count 如果它是 0 尝试先将 cmb 添加到Form之前分配SelectedIndex

编辑:

    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, 可能会有所帮助。

可能是因为组合是在 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;
    }
}

}

您可能想尝试SelectedItem而不是SelectedValue ,并为它分配您想要的类。 例如:

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

由于不止一项的值可以为 2(就ComboBox ,无论如何),我认为您将难以通过SelectedValue设置值。

暂无
暂无

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

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