Как вставить поле "Пустое" в ComboBox, связанное с DataTable
У меня есть поле со списком в приложении WinForms, в котором элемент может быть выбран, но это необязательно. Поэтому мне нужен "пустой" первый элемент, указывающий, что значение не было установлено.
Поле со списком привязано к возвращаемому DataTable из хранимой процедуры (я не приношу извинения за венгерскую нотацию в элементах управления пользовательским интерфейсом: p):
DataTable hierarchies = _database.GetAvailableHierarchies(cmbDataDefinition.SelectedValue.ToString()).Copy();//Calls SP
cmbHierarchies.DataSource = hierarchies;
cmbHierarchies.ValueMember = "guid";
cmbHierarchies.DisplayMember = "ObjectLogicalName";
Как вставить такой пустой элемент?
У меня есть доступ к изменению SP, но я бы предпочел не "загрязнять" его логикой пользовательского интерфейса.
Обновление: Это был DataTable.NewRow(), который я забыл, спасибо. Я полностью изменил вас (все три ответа до сих пор). Я пытаюсь заставить шаблон Iterator работать, прежде чем решиться на "ответ"
Обновление: Я думаю, что это редактирование помещает меня в землю сообщества Wiki, я решил не указывать один ответ, так как все они имеют достоинство в контексте своих доменов. Спасибо за коллективный ввод.
Ответы
Ответ 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
Затем установите dataview как DataSource
для ComboBox
.
-
Если вы действительно не хотите добавлять новую строку, как указано выше. Вы можете разрешить пользователю устанавливать значение ComboBox
в значение null, просто обработав событие "Удалить". Когда пользователь нажимает клавишу "Удалить", установите для параметра SelectedIndex
значение -1. Вы также должны установить ComboBox.DropDownStyle
в DropDownList
. Поскольку это не позволит пользователю редактировать значения в ComboBox
.
Ответ 2
cmbHierarchies.SelectedIndex = -1;
Ответ 3
Я обычно создаю итератор для этого типа вещей. Это позволяет избежать загрязнения ваших данных и хорошо работает с привязкой данных:
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
вставьте пустую строку в свой datatable и проверьте ее в validation/update/create
Ответ 5
Нельзя добавить новый DataRow в DataTable, прежде чем привязывать его к вашему DataSource?
Для достижения этой цели вы можете использовать функцию NewRow DataTable:
http://msdn.microsoft.com/en-us/library/system.data.datatable.newrow.aspx
Ответ 6
Я нашел другое решение:
Сразу после создания таблицы данных (перед использованием заливки) добавьте новую строку и используйте метод AcceptChanges в таблице. Новая запись получит RowState = Unchanged и не будет добавлена в базу данных, но будет видна в вашем datatable и combobox.
DataTable dt = new DataTable();
dt.Rows.Add();
dt.AcceptChanges();
...
dt.Fill("your query");
Ответ 7
Я написал этот метод на основе предложений здесь Джейсона Джексона:
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 может быть чрезмерным для вашей ситуации.
Предложения и предложения приветствуются.
Ответ 8
Er, не можете ли вы просто добавить элемент по умолчанию в ComboBox после привязки данных?
Ответ 9
Я бы привязал данные, а затем ввел пустой элемент в позицию 0 с помощью метода ComboxBox.Items.Insert. Подобно тому, что предлагалось, но добавляет элемент вверх.
Ответ 10
У меня была аналогичная задача. В качестве части события загрузки формы я устанавливаю SelectedIndex элемента управления на -1
т
private void Form1_Load(object sender, EventArgs e)
{
this.TableAdapter.Fill(this.dsListOfCampaigns.EvolveCampaignTargetListMasterInfo);
this.comboCampaignID.SelectedIndex = -1;
}
Эффективно, поле со списком заполняется и выбирается первый элемент. Затем элемент не выбран. Не может быть жизнеспособным решением для всех случаев.
Ответ 11
this.recieptDateTimePicker.SelectedIndex = -1;
this.dateCompoBox.SelectedIndex = -1;
Ответ 12
Я нашел этот способ:
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
Вместо того, чтобы добавить новую строку в ваш datatable, просто привяжите данные к combobox и при загрузке установите 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" или что-то, что мне нужно обстоятельства.