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つの回答すべて)。「答え」を決定する前に、Iterator パターンを機能させようとしています。

更新:この編集により、私はコミュニティ Wiki の世界に足を踏み入れたと思います。単一の回答を指定しないことに決めました。それらはすべて、ドメインのコンテキストでメリットがあるためです。まとめてご意見をお寄せいただきありがとうございます。

4

13 に答える 13

27

できることは 2 つあります。

  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のように設定しComboBoxます。

  2. 上記のように新しい行を追加したくない場合。ComboBox「削除」キー押下イベントを処理するだけで、ユーザーが値を null に設定できるようにすることができます。ユーザーが Delete キーを押したときに、SelectedIndex-1 に設定します。にも設定する必要がありComboBox.DropDownStyle ますDropDownList。これにより、ユーザーは の値を編集できなくなります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 コンボ ボックスは IEnumerable ではなく、IList を必要としています。よりコストのかかる操作は、リストを作成することです。このコードは非常に簡潔であり、私は実際にはコンパイルしていません。

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

別の解決策を見つけました:

データ テーブルが作成された直後 (fill を使用する前) に、新しい行を追加し、AcceptChanges メソッドをテーブルに使用します。新しいレコードは RowState = Unchanged になり、データベースには追加されませんが、データテーブルとコンボボックスに表示されます。

   DataTable dt = new DataTable();
    dt.Rows.Add();
    dt.AcceptChanges();
    ...
    dt.Fill("your query");
于 2011-06-09T11:38:43.090 に答える
2

DataSource にバインドする前に、新しい DataRow を DataTable に追加できませんか?

これを実現するには、DataTable の NewRow 関数を使用できます。

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

于 2008-10-14T01:05:19.380 に答える
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 は状況によってはやり過ぎになる可能性があります。

コメントや提案を歓迎します。

于 2010-10-21T10:57:03.720 に答える
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 に設定します。

すなわち

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

データテーブルに新しい行を追加する代わりに、データをコンボボックスにバインドし、ロード時に SelectedIndex を -1 に設定します。これにより、ユーザーが項目を選択するまで、選択は null になります。

これは、現在のプロジェクトの 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 に答える
0

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

于 2013-04-04T13:54:04.343 に答える
0

えーと、データ バインド後に ComboBox に既定の項目を追加することはできませんか?

于 2008-10-14T01:41:13.380 に答える
0

データをバインドしてから、ComboxBox.Items.Insert メソッドを使用して位置 0 に空白の項目を挿入します。Flipdoubt が提案したものと似ていますが、アイテムを一番上に追加します。

于 2008-10-14T08:56:07.493 に答える