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

℡╲_俬逩灬. 提交于 2019-12-18 06:57:18

问题


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.

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

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

回答1:


You've set the value member to be "Id" but you're trying to use "AnswerId" as the selected value.

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?

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.




回答2:


This is just a guess, but maybe, the ComboBox doesn't bind the data in the DataSource until it's drawn. Check cmb.Items.Count in the line before the SelectedIndex = 1. If it is 0 try to first add the cmb to the Form before assigning 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; 
    } 



回答3:


You need to set the cmb.DataBindings and this might help.




回答4:


Maybe because the combo is created during the Form_load event. Try to create your combo in the constructor and set the selection in 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;
    }
}

}



回答5:


You may want to try SelectedItem instead of SelectedValue, and assigning the class that you want to it. 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.



来源:https://stackoverflow.com/questions/3201340/c-sharp-why-isnt-it-possible-to-set-the-selectedvalue-of-a-dynamically-created

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!