Подтвердить что ты не робот

Как вставить поле "Пустое" в 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, я решил не указывать один ответ, так как все они имеют достоинство в контексте своих доменов. Спасибо за коллективный ввод.

4b9b3361

Ответ 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

Ответ 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" или что-то, что мне нужно обстоятельства.