代码之家  ›  专栏  ›  技术社区  ›  johnc

如何在绑定到数据表的组合框中插入“空”字段

  •  17
  • johnc  · 技术社区  · 16 年前

    我在WinForms应用程序上有一个组合框,可以在其中选择一个项目,但这不是必需的。因此,我需要一个“空”的第一项来表示没有设置任何值。

    组合框绑定到从存储过程返回的数据表(我不为UI控件上的匈牙利符号道歉:p):

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

    如何插入这样一个空项目?

    我确实可以更改SP,但我真的不希望用UI逻辑“污染”它。

    更新: 这是我空白的dataTable.newrow(),谢谢。我已经把你们都改了(到目前为止,这三个答案都是)。在决定“答案”之前,我正在尝试让迭代器模式工作。

    更新: 我认为这篇编辑文章让我进入了社区维基领域,我决定不指定一个单一的答案,因为它们在各自领域中都有优势。感谢您的集体意见。

    13 回复  |  直到 9 年前
        1
  •  24
  •   abatishchev Marc Gravell    14 年前

    你可以做两件事:

    1. 将空行添加到 DataTable 从存储过程返回的。

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

      创建一个数据视图,并使用ObjectLogicalName列对其进行排序。这将使新添加的行成为DataView中的第一行。

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

      然后将数据视图设置为 DataSource ComboBox .

    2. 如果您真的不想像上面提到的那样添加新行。您可以允许用户设置 组合框 值为空,只需处理“删除”按键事件。当用户按Delete键时,设置 SelectedIndex 到1。你也应该设置 ComboBox.DropDownStyle DropDownList . 因为这将阻止用户编辑 组合框 .

        2
  •  14
  •   abatishchev Marc Gravell    14 年前
    cmbHierarchies.SelectedIndex = -1;
    
        3
  •  8
  •   Jason Jackson    16 年前

    我通常为这种类型的东西创建一个迭代器。它可以避免污染您的数据,并且可以很好地处理数据绑定:

    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";
    
        4
  •  3
  •   Steven A. Lowe    16 年前

    在数据表中插入空行,并在验证/更新/创建中检查它

        5
  •  2
  •   Mark    16 年前

    在将新数据行绑定到数据源之前,不能将其添加到数据表中?

    您可以使用数据表的newrow函数来实现这一点:

    http://msdn.microsoft.com/en-us/library/system.data.datatable.newrow.aspx

        6
  •  2
  •   Ray    13 年前

    我找到了另一个解决方案:

    在创建数据表之后(在使用fill之前),添加新行,并使用acceptChanges方法将其添加到表中。新记录将获得rowstate=unchanged,并且不会添加到数据库中,但会在数据表和组合框中可见。

       DataTable dt = new DataTable();
        dt.Rows.Add();
        dt.AcceptChanges();
        ...
        dt.Fill("your query");
    
        7
  •  1
  •   abatishchev Marc Gravell    14 年前

    我根据Jason Jackson的建议编写了这个方法:

    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')
    

    这将允许显示连接在组合框中的多个列,同时将值成员保留为单个标识符+它将迭代器块与bindingSource一起使用,bindingSource可能会因您的情况而过度终止。

    欢迎提出建议和建议。

        8
  •  0
  •   flipdoubt    16 年前

    呃,您不能在数据绑定之后向组合框添加一个默认项吗?

        9
  •  0
  •   Arry    16 年前

    我将绑定数据,然后使用comboxbox.items.insert方法在位置0插入一个空白项。类似于FlipQuestion的建议,但它会将项目添加到顶部。

        10
  •  0
  •   Rob    12 年前

    我也遇到过类似的挑战。作为窗体加载事件的一部分,我将控件的SelectedIndex设置为-1

    工业工程

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

    有效地,组合框被填充,第一个项目被选中。然后取消选择项目。可能不是所有情况下的可行解决方案。

        11
  •  0
  •   Sujith Radhakrishnan    11 年前

    this.recieptDateTimePicker.SelectedIndex = -1; this.datecompobox.selectedIndex=-1;

        12
  •  0
  •   Zen    11 年前

    我是这样发现的:

        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;
    
        13
  •  0
  •   joshman1019    10 年前

    不要向数据表中添加新行,只需将数据绑定到组合框,并在加载时将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”或在这种情况下需要的任何值。