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ロジックでそれを「汚染」しないことを本当に望んでいます。
pdate:おかげで私が非表示にしたのはDataTable.NewRow()でした。私はあなたすべてを更新しました(とにかくこれまでのところ3つの回答すべて)。 「答え」を決める前に、イテレーターパターンを機能させようとしています
更新:この編集によりコミュニティウィキの土地に入ると思います。すべてのドメインのコンテキストでメリットがあるため、単一の回答を指定しないことにしました。集合的なご意見ありがとうございます。
できることは2つあります。
ストアドプロシージャから返される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
として設定します。
上記のように本当に新しい行を追加したくない場合。 "Delete" keypressイベントを処理するだけで、ユーザーがComboBox
値をnullに設定できるようにすることができます。ユーザーがDeleteキーを押したら、SelectedIndex
を-1に設定します。また、ComboBox.DropDownStyle
をDropDownList
に設定する必要があります。これにより、ユーザーがComboBox
の値を編集できなくなります。
cmbHierarchies.SelectedIndex = -1;
私は通常、この種のイテレータを作成します。それはあなたのデータを汚染することを避け、データバインディングでうまく機能します:
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"] };
}
免責事項:私はこのコードをコンパイルしていませんが、このパターンを何度も使用しています。
注:私は過去2年間、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";
データテーブルに空白行を挿入し、検証/更新/作成で確認します
私は別の解決策を見つけました:
データテーブルが作成された直後(fillを使用する前)に、新しい行を追加し、テーブルにAcceptChangesメソッドを使用します。新しいレコードはRowState = Unchangedを取得し、データベースに追加されませんが、データテーブルとコンボボックスに表示されます。
DataTable dt = new DataTable();
dt.Rows.Add();
dt.AcceptChanges();
...
dt.Fill("your query");
DataSourceにバインドする前に、DataTableに新しいDataRowを追加できませんか?
これを行うには、DataTableのNewRow関数を使用できます。
http://msdn.Microsoft.com/en-us/library/system.data.datatable.newrow.aspx
このメソッドは、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でイテレーターブロックを使用します。
コメントや提案は大歓迎です。
私はこの方法を見つけました:
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;
えっと、データバインド後にComboBoxにデフォルトの項目を追加するだけではどうですか。
私も同じような挑戦をしました。フォーム読み込みイベントの一部として、コントロールのSelectedIndexを-1に設定しました
すなわち
private void Form1_Load(object sender, EventArgs e)
{
this.TableAdapter.Fill(this.dsListOfCampaigns.EvolveCampaignTargetListMasterInfo);
this.comboCampaignID.SelectedIndex = -1;
}
事実上、コンボボックスにデータが入力され、最初の項目が選択されます。その後、アイテムの選択が解除されます。すべてのケースで実行可能なソリューションとは限りません。
データテーブルに新しい行を追加する代わりに、データをコンボボックスにバインドし、ロード時に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」などのデフォルト値のタイプや、状況に応じて必要なものを生成します。
this.recieptDateTimePicker.SelectedIndex = -1;
this.dateCompoBox.SelectedIndex = -1;
データをバインドし、ComboxBox.Items.Insertメソッドを使用して位置0に空白のアイテムを挿入します。フリップダウトが提案したものに似ていますが、アイテムを上部に追加します。