19

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

组合框绑定到从存储过程返回的 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 个答案)。在决定“答案”之前,我试图让迭代器模式工作

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

4

13 回答 13

27

你可以做两件事:

  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
    

    然后将数据视图设置DataSourceComboBox.

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

于 2008-10-14T01:29:25.260 回答
15
cmbHierarchies.SelectedIndex = -1;
于 2009-04-28T07:52:22.453 回答
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";
于 2008-10-14T01:17:06.470 回答
3

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

于 2008-10-14T01:05:35.977 回答
2

不能在将新的 DataRow 绑定到 DataSource 之前将它添加到 DataTable 吗?

您可以使用 DataTable 的 NewRow 函数来实现:

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

于 2008-10-14T01:05:19.380 回答
2

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

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

   DataTable dt = new DataTable();
    dt.Rows.Add();
    dt.AcceptChanges();
    ...
    dt.Fill("your query");
于 2011-06-09T11:38:43.090 回答
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 );

再往下,使用 Selected Value 的地方:

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

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

欢迎评论和建议。

于 2010-10-21T10:57:03.720 回答
0

呃,数据绑定后不能给ComboBox添加一个默认项吗?

于 2008-10-14T01:41:13.380 回答
0

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

于 2008-10-14T08:56:07.493 回答
0

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

IE

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

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

于 2012-06-28T03:36:14.497 回答
0

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

于 2013-04-04T13:54:04.343 回答
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;
于 2013-08-08T13:32:11.387 回答
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,那么它会被跳过,或者我将生成某种类型的默认值,例如“N/A”或在这种情况下我需要的任何值。

于 2014-10-19T22:09:32.010 回答