Как вставить пустое поле в ComboBox, привязанное к DataTable - PullRequest
17 голосов
/ 14 октября 2008

У меня есть поле со списком в приложении 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 (), на котором я остановился, спасибо. Я обновил вас всех (все 3 ответа так или иначе пока). Я пытаюсь заставить работать шаблон Итератора, прежде чем выбрать «ответ»

Обновление: Я думаю, что это изменение помещает меня в вики сообщества, я решил не указывать ни одного ответа, так как все они имеют свои достоинства в контексте своих доменов. Спасибо за ваш коллективный вклад.

Ответы [ 13 ]

24 голосов
/ 14 октября 2008

Есть две вещи, которые вы можете сделать:

  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 на ноль, просто обрабатывая событие нажатия клавиши «Удалить». Когда пользователь нажимает клавишу Delete, установите SelectedIndex в -1. Вы также должны установить ComboBox.DropDownStyle на DropDownList. Поскольку это помешает пользователю редактировать значения в ComboBox.

14 голосов
/ 28 апреля 2009
cmbHierarchies.SelectedIndex = -1;
8 голосов
/ 14 октября 2008

Я обычно создаю итератор для такого типа вещей. Это позволяет избежать загрязнения ваших данных и хорошо работает с привязкой данных:

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 голосов
/ 14 октября 2008

вставьте пустую строку в таблицу данных и проверьте ее в проверке / обновлении / создании

2 голосов
/ 09 июня 2011

Я нашел другое решение:

Сразу после создания таблицы данных (перед использованием заливки) добавьте новую строку и используйте метод AcceptChanges для таблицы. Новая запись получит RowState = Unchanged и не будет добавлена ​​в базу данных, но будет видна в вашем списке данных и в выпадающем списке.

   DataTable dt = new DataTable();
    dt.Rows.Add();
    dt.AcceptChanges();
    ...
    dt.Fill("your query");
2 голосов
/ 14 октября 2008

Не можете ли вы добавить новый DataRow в DataTable, прежде чем привязать его к вашему DataSource?

Вы можете использовать функцию NewRow DataTable для достижения этой цели:

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

1 голос
/ 21 октября 2010

Я написал этот метод, основываясь на предложениях Джейсона Джексона:

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 может быть излишним для вашей ситуации.

Комментарии и предложения приветствуются.

0 голосов
/ 20 октября 2014

Вместо добавления новой строки в таблицу данных, просто привяжите данные к списку и при загрузке установите 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» или все, что мне нужно в обстоятельства.

0 голосов
/ 08 августа 2013

Я нашел этот путь:

    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;
0 голосов
/ 04 апреля 2013

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...