如何在绑定到DataTable的ComboBox中插入“Empty”字段

时间:2008-10-14 00:57:34

标签: c# combobox

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

组合框绑定到从存储过程返回的DataTable(我没有在我的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(),谢谢。我已经对你进行了修改(到目前为止所有3个答案)。在决定'回答'之前,我试图让Iterator模式正常工作

更新:我认为这个编辑让我进入了社区维基,我决定不指定一个答案,因为它们都有其领域背景的优点。感谢您的集体意见。

13 个答案:

答案 0 :(得分:24)

您可以做两件事:

  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
    

    然后将数据视图设置为DataSource的{​​{1}}。

  2. 如果你真的不想像上面提到的那样添加新行。您可以通过简单地处理“删除”按键事件,允许用户将ComboBox值设置为null。当用户按Delete键时,将ComboBox设置为-1。您还应将SelectedIndex设置为ComboBox.DropDownStyle。因为这会阻止用户编辑DropDownList

  3. 中的值

答案 1 :(得分:14)

cmbHierarchies.SelectedIndex = -1;

答案 2 :(得分: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";

答案 3 :(得分:3)

在数据表中插入一个空行,并在validation / update / create

中检查它

答案 4 :(得分:2)

在将DataRow绑定到DataSource之前,是否不能将新DataRow添加到DataTable中?

您可以使用DataTable的NewRow功能来实现此目的:

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

答案 5 :(得分:2)

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

在创建数据表之后(在使用填充之前),添加新行并对表使用AcceptChanges方法。新记录将获得RowState = Unchanged,并且不会添加到数据库中,但会在数据表和组合框中显示。

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

答案 6 :(得分:1)

我根据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')

这将允许显示在ComboBox中连接的多个列,同时将Value成员保持为单个标识符+它使用带有BindingSource的迭代器块,BindingSource可能对您的情况有点过分。

欢迎提出建议和建议。

答案 7 :(得分:0)

呃,你不能只在数据绑定后向ComboBox添加一个默认项吗?

答案 8 :(得分:0)

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

答案 9 :(得分:0)

我遇到了类似的挑战。作为表单加载事件的一部分,我将控件的SelectedIndex设置为-1

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

实际上,填充了组合框并选择了第一个项目。然后取消选择该项目。对于所有情况而言,可能不是一个可行的解决方案。

答案 10 :(得分:0)

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

答案 11 :(得分: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;

答案 12 :(得分:0)

不是向数据表添加新行,而是将数据绑定到组合框,并在加载时将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然后它被跳过,或者我将生成某种类型的默认值,例如&#34; N / A&#34;或者在这种情况下我需要什么。