2010-07-08 26 views
4

我在一個類中創建了一個組合框,並且想要爲該組合框設置選定的值。但是當我這樣做時,selectedValue保持爲空,當我嘗試設置selectedIndex時,我得到一個ArgumentOutOfRangeException。C#爲什麼不能設置動態創建的組合框的selectedValue?

代碼:

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

回答

10

你設定值的成員是「ID」,但你正在嘗試使用「AnswerId」作爲選擇的值。

如果沒有更多的細節,這是很難說爲什麼設置SelectedIndex被拋出ArgumentOutOfRangeException - 也許是組合框忽略不有一個「id」屬性的所有值,從而給你的值,因此選擇指數1是不可能的?

編輯:好的,所以它看起來只是在它變得可見時才實際進行綁定 - 或者在過程的某個階段。我嘗試了幾件事來加速這一點,但他們似乎沒有幫助。你可以做的是推遲您的選擇:

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

這是一個醜陋的解決方法,但它至少應該幫助您獲得持續的時刻。

+0

我的組合它是ValueMember是Id類型的long類型。您提到的AnswerId也是long類型的。我看起來組合還沒有'綁定'數據源。因爲當我在實際表單上設置selectedValue時,它可以工作。問題是,我無法在類中設置SelectedValue,但我可以將其設置在控件佔據他的位置的表單上。 – Martijn 2010-07-08 07:23:15

+0

@Martijn:如果你可以添加一個簡短的*完整的*程序,這對我們自己來說是非常有用的。它不需要很複雜 - 但目前我們只是猜測。 – 2010-07-08 07:30:21

+0

@Jon:我用一個完整的程序編輯了我的startpost,說明了我的情況。 – Martijn 2010-07-08 07:55:27

3

這只是一個猜測,但也許ComboBox不會綁定DataSource中的數據,直到它被繪製爲止。在SelectedIndex = 1之前檢查cmb.Items.Count。如果它是0,則在分配SelectedIndex之前,先嚐試將cmb添加到Form

編輯:

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

項目數量爲零。當我將控件添加到表單中時,我可以設置SelectedValue(我從Tag屬性獲得..) – Martijn 2010-07-08 07:25:08

+0

這是Jon的解決方法... – Hinek 2010-07-08 09:45:33

1

您需要設置cmb.DataBindings和this可能的幫助。

0

您可能需要嘗試SelectedItem而不是SelectedValue,然後指定您想要的類。例如:

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

由於不止一個項目可以有2的值(至於ComboBox知道,反正),我認爲你將很難通過設置SelectedValue值。

+0

我試過這個,但是任何選中的****(item ,索引,值)不起作用。 – Martijn 2010-07-08 08:58:05

+0

您可能確實想要在分配新數據源後立即添加值,但在該數據在列表框中可用之前。 嘗試綁定事件'DataSourceChanged'並在那裏設置選定的項目。 – rakuo15 2010-07-08 09:08:17

+0

我應該在設置數據源屬性之前還是之後註冊該事件? – Martijn 2010-07-08 09:19:41

1

也許是因爲組合是在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; 
    } 
} 

}