2008-10-14 34 views
17

我在WinForms應用程序中有一個組合框,其中可以選擇一個項目,但它不是強制性的。因此,我需要一個'空'的第一項來表示沒有設置值。如何在綁定到DataTable的ComboBox中插入'Empty'字段

的組合框綁定到從存儲過程(我提供我的UI控件沒有道歉匈牙利表示法:P):返回一個DataTable存在

DataTable hierarchies = _database.GetAvailableHierarchies(cmbDataDefinition.SelectedValue.ToString()).Copy();//Calls SP 
cmbHierarchies.DataSource = hierarchies; 
cmbHierarchies.ValueMember = "guid"; 
cmbHierarchies.DisplayMember = "ObjectLogicalName"; 

我如何可以插入這樣一個空的項目?

我確實有權更改SP,但我真的不想用UI邏輯「污染」它。

更新:這是DataTable.NewRow(),我已經空白,謝謝。我已經改變了你所有的(到目前爲止所有3個答案)。我想之前我決定的「答案」,讓迭代器模式工作

更新:我覺得這個修改使我在社區維基土地,我決定不指定一個唯一的答案,因爲他們都有在他們的領域中是值得的。感謝您的集體投入。

回答

23

有兩件事情可以做:

  1. 添加一個空行到DataTable是從存儲過程返回。

    DataRow emptyRow = hierarchies.NewRow(); 
    emptyRow["guid"] = ""; 
    emptyRow["ObjectLogicalName"] = ""; 
    hierarchies.Rows.Add(emptyRow); 
    

    創建DataView並使用ObjectLogicalName列對其進行排序。這將使新添加的行成爲DataView中的第一行。

    DataView newView =   
        new DataView(hierarchies,  // source table 
        "",        // filter 
        "ObjectLogicalName",   // sort by column 
        DataViewRowState.CurrentRows); // rows with state to display 
    

    然後設置數據視圖作爲ComboBoxDataSource

  2. 如果您確實不想添加如上所述的新行。您只需處理「刪除」按鍵事件即可允許用戶將ComboBox值設置爲空。當用戶按Delete鍵時,將SelectedIndex設置爲-1。您還應該將ComboBox.DropDownStyle設置爲DropDownList。因爲這會阻止用戶編輯ComboBox中的值。

3

插入您的數據表中的空白行,並在驗證/更新檢查它/創建

+0

更好的辦法是用您的真實查詢「選擇」一個空行和UNION。這會讓你的數據庫保持完好。 – BoltBait 2008-10-14 01:08:53

+0

@ [BoltBait]:除了他已經表示他不想改變他的存儲過程 – 2008-10-14 01:09:56

+4

我更喜歡將UI要求保留在數據庫之外。 – 2009-08-25 18:46:48

8

我通常爲這種類型的事物創建一個迭代器。它避免了污染數據,以及與數據綁定效果很好:

DataTable hierarchies = _database.GetAvailableHierarchies(cmbDataDefinition.SelectedValue.ToString()).Copy();//Calls SP 
cmbHierarchies.DataSource = GetDisplayTable(hierarchies); 
cmbHierarchies.ValueMember = "guid"; 
cmbHierarchies.DisplayMember = "ObjectLogicalName"; 

... 

private IEnumerable GetDisplayTable(DataTable tbl) 
{ 
    yield return new { ObjectLogicalName = string.Empty, guid = Guid.Empty }; 

    foreach (DataRow row in tbl.Rows) 
     yield return new { ObjectLogicalName = row["ObjectLogicalName"].ToString(), guid = (Guid)row["guid"] }; 
} 

免責聲明:我沒有編譯的代碼,但使用這種模式很多次。

注:我在WPF和ASP.Net土地在過去幾年一直在。顯然,WinForms組合框需要一個IList,而不是IEnumerable。一個更昂貴的操作將是創建一個列表。這種代碼真的流的,簡潔,我真的,真的沒有編譯它:

DataTable hierarchies = _database.GetAvailableHierarchies(cmbDataDefinition.SelectedValue.ToString()).Copy(); 
List<KeyValuePair<string, Guid>> list = new List<KeyValuePair<string, Guid>>(hierarchies.Rows.Cast<DataRow>().Select(row => new KeyValuePair<string, Guid>(row["Name"].ToString(), (Guid)row["Guid"]))); 
list.Insert(0, new KeyValuePair<string,Guid>(string.Empty, Guid.Empty)); 
cmbHierarchies.DataSource = list; 
cmbHierarchies.ValueMember = "Value"; 
cmbHierarchies.DisplayMember = "Key"; 
+0

我得到一個「Complex DataBinding接受作爲數據源的IList或IListSource」錯誤,並且無法找到IEnumerable和IList之間的轉換(如果您習慣在WPF中執行此操作,我在WinForms中) – johnc 2008-10-14 01:29:42

+0

已經在ASP.Net領域有一段時間了,但回想一下在WPF中使用這種模式。我有3年沒有與WinForms合作過。如果這需要一個列表,那麼我會建議一個類似的策略,只需創建一個列表而不是使用迭代器。 – 2008-10-14 01:33:12

0

呃,難道你不能在數據綁定後向ComboBox添加默認項目嗎?

0

我會綁定數據,然後使用ComboxBox.Items.Insert方法在位置0處插入一個空白項目。類似於現在提出的疑點,但是它將該項目添加到頂部。

13
cmbHierarchies.SelectedIndex = -1; 
1

我寫了基於此建議由傑森·傑克遜這個方法:

private IEnumerable<KeyValuePair<object,object>> GetDisplayTable(DataTable dataTable, DataColumn ValueMember, string sep,params DataColumn[] DisplayMembers) 
{ 
    yield return new KeyValuePair<object,object>("<ALL>",null); 

    if (DisplayMembers.Length < 1) 
     throw new ArgumentException("At least 1 DisplayMember column is required"); 

    foreach (DataRow r in dataTable.Rows) 
    { 
     StringBuilder sbDisplayMember = new StringBuilder(); 
     foreach(DataColumn col in DisplayMembers) 
     { 
      if (sbDisplayMember.Length > 0) sbDisplayMember.Append(sep); 
      sbDisplayMember.Append(r[col]); 
     } 
     yield return new KeyValuePair<object, object>(sbDisplayMember.ToString(), r[ValueMember]); 
    } 
} 

用法:

bindingSource1.DataSource = GetDisplayTable(
      /*DataTable*/typedDataTable, 
      /*ValueMember*/typedDataTable.IDColumn, 
      /*DisplayColumn Seperator*/" - ", 
      /*List of Display Columns*/ 
      typedDataTable.DB_CODEColumn, 
      typedDataTable.DB_NAMEColumn); 

comboBox1.DataSource = bindingSource1; 
comboBox1.DisplayMember = "Key"; 
comboBox1.ValueMember = "Value"; 

//another example without multiple display data columns: 
bindingSource2.DataSource = GetDisplayTable(
      /*DataTable*/typedDataTable, 
      /*ValueMember*/typedDataTable.IDColumn, 
      /*DisplayColumn Seperator*/null, 
      /*List of Display Columns*/ 
       typedDataTable.DESCColumn); 

進一步回落,其中選擇的值消耗:

if (comboBox1.SelectedValue != null) 
    // Do Something with SelectedValue 
else 
    // All was selected (all is my 'empty') 

這將允許顯示在ComboBox中串聯的幾個列,同時將Value成員保留爲單個標識符+它將BindingSource與迭代器塊一起使用,BindingSource可能會爲您的情況矯枉過正。

評論和建議歡迎。

2

我找到了另一種解決方案:

創建剛過數據表(使用前填寫),添加新行並使用AcceptChanges方法表。新記錄將得到RowState = Unchanged,並且不會被添加到數據庫,但會在您的數據表和組合框中可見。

DataTable dt = new DataTable(); 
    dt.Rows.Add(); 
    dt.AcceptChanges(); 
    ... 
    dt.Fill("your query"); 
0

我有類似的挑戰。正如表格負載事件的一部分予設定的控制的爲-1

private void Form1_Load(object sender, EventArgs e) 
{   
    this.TableAdapter.Fill(this.dsListOfCampaigns.EvolveCampaignTargetListMasterInfo); 
    this.comboCampaignID.SelectedIndex = -1; 
} 

有效地,組合框填充和中的第一項被選擇的SelectedIndex。然後該項目被取消選擇。可能不是所有情況下可行的解決方案。

0

this.recieptDateTimePicker.SelectedIndex = -1; this.dateCompoBox.SelectedIndex = -1;

0

我發現這種方式:

DataTable hierarchies = new DataTable(); 

    cmbHierarchies.BeginUpdate(); 
    cmbHierarchies.ValueMember = this.Value; 
    cmbHierarchies.DisplayMember = this.Display; 
    hierarchies = DataView.ToTable(); 
    cmbHierarchies.DataSource = table; 
    cmbHierarchies.EndUpdate(); 

    //Add empty row 
    DataRow row = table.NewRow(); 
    table.Rows.InsertAt(row, 0); 
    cmbHierarchies.SelectedIndex = 0; 
0

,而不是新增一行到你的數據表,只需將數據綁定到ComboBox和負載的SelectedIndex設置爲-1。這將導致選擇爲空,直到用戶選擇一個項目。

我從我目前的一個項目中截取了這個。

 Attorney_List_CB.DataSource = DA_Attorney_List.BS.DataSource; 
     Attorney_List_CB.DisplayMember = "Attorney Name"; 
     Attorney_List_CB.SelectedIndex = -1;  

爲了清除選擇,我通常會插入一個按鈕,將SelectedIndex設置回-1。

private void Clear_Selection_BTN_Click(object sender, EventArgs e) 
    { 
     Attorney_List_CB.SelectedIndex = -1; // Clears user selection 
    } 

最後,一旦驗證我的表格上的數據,如果任何組合框的selectedIndex是-1,那麼它被跳過,或我會產生某種類型的默認值,例如「N/A」或任何的我需要在這種情況下。

相關問題