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; }
}
}
}
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.
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;
}
您需要设置 cmb.DataBindings, 这可能会有所帮助。
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;
}
}
}
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
.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.