Динамически добавьте элемент в столбец DataGridView ComboBox, введя в ячейку - PullRequest
0 голосов
/ 21 января 2019

У меня есть DataGridView, в котором есть столбец ComboBox, и я должен обновить возможные значения каждого ComboBox, когда появится его раскрывающийся список. Я также должен сделать ComboBox es способными иметь пользовательские значения. Когда вводится новое значение, оно должно быть добавлено в список возможных значений. Проблема в том, что я получаю бесконечно много DataError событийных триггеров (ящиков с сообщениями об ошибках), я знаю, как справиться с этим, просто изменив поле в DataGridViewDataErrorEventArgs объекте, но я знаю, что это неправильный способ обработки:

private void DataGridView1_DataError(object sender, DataGridViewDataErrorEventArgs e)
{
    e.Cancel = false;
}

Если я делаю это неправильно, после выбора значения из выпадающего списка или ввода нового значения, CellValueChanged срабатывает, но закрытое ComboBox отображает не текущее значение, а уже существующее значение ( первый в списке).

В следующем коде подкласс Form равен Form2, начальные значения сохраняются в поле str, и вызывается метод UpdatePossibleValues для обновления возможных значений во всех ComboBox внутри единственного столбца. в представлении таблицы данных a DataGridViewComboBoxColumn:

public Form2()
{
    InitializeComponent();

    dataGridView1.EditingControlShowing += DataGridView1_EditingControlShowing;

    UpdatePossibleValues();
}

internal List<string> str = new List<string>()
{
    "val1",
    "val2"
};

private void DataGridView1_EditingControlShowing(object sender, 
    DataGridViewEditingControlShowingEventArgs e)
{
    if (dataGridView1.CurrentCell == null ||
        dataGridView1.CurrentCell.OwningColumn == null ||
        dataGridView1.CurrentCell.OwningColumn.Name != "column1")
    {
        return;
    }
    var combo = e.Control as DataGridViewComboBoxEditingControl;
    if (combo == null)
    {
        return;
    }

    var cb = combo as ComboBox;
    UpdatePossibleValues(cb);
    cb.DropDownStyle = ComboBoxStyle.DropDown; // this makes the ComboBoxes editable
    cb.Validating += Cb_Validating;
}

private void Cb_Validating(object sender, System.ComponentModel.CancelEventArgs e)
{
    var cbo = sender as ComboBox;
    string t = cbo.Text;

    var cell = (DataGridViewComboBoxCell)dataGridView1.CurrentCell;

    // add the value to the list if it is not there
    if (!string.IsNullOrEmpty(t) &&
        !cbo.Items.Contains(t))
    {
        str.Add(t);

        UpdatePossibleValues(cbo);

        cell.Value = t;

        e.Cancel = false;
    }
}

private void UpdatePossibleValues(ComboBox cb = null)
{
    if (cb == null)
    {
        var col = dataGridView1.Columns[0] as DataGridViewComboBoxColumn;

        col.Items.Clear();
        foreach (string s in str)
        {
            col.Items.Add(s);
        }
    }
    else
    {
        cb.Items.Clear();
        foreach (string s in str)
        {
            cb.Items.Add(s);
        }
    }
}

Скриншоты:

normal use

data error

1 Ответ

0 голосов
/ 21 января 2019

Для динамического добавления элемента в DataGridViewComboBoxColumn:

  1. Hanlde EditingControlShowing и получите DataGridViewComboBoxEditingControl
  2. Установить управление редактированием DropDownStyle на DropDown
  3. Обработайте Validating событие редактирования редактирования и убедитесь, что вы подключили обработчик события только один раз.
  4. Проверьте, не существует ли Text элемента управления для редактирования в элементах:
    • Добавить его в источник данных столбца
    • Затем сбросьте источник данных столбца, задав для него значение null и снова назначив источник данных.

Примечания:

  • Если у вас есть несколько полей со списком, убедитесь, что вы используете разные источники данных для полей со списком и обновите соответствующий источник данных при проверке события.

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

* ** 1038 тысяча тридцать семь * Пример

В следующем примере показано DataGridView с двумя DataGridViewComboBoxColumn, которые для второго можно добавить новые значения, введя в поле со списком во время выполнения.

Чтобы запустить пример, создайте Form и добавьте DataGridView в новую форму и просто скопируйте и вставьте следующий код в форму:

private List<String> comboSource1;
private List<String> comboSource2;
protected override void OnLoad(EventArgs e)
{
    base.OnLoad(e);
    comboSource1 = new List<string> { "A", "B" };
    comboSource2 = new List<string> { "1", "2" };

    var dt = new DataTable();
    dt.Columns.Add("C1");
    dt.Columns.Add("C2");
    dt.Rows.Add("A", "1");
    dt.Rows.Add("B", "2");

    var c1 = new DataGridViewComboBoxColumn();
    c1.Name = "C1";
    c1.DataPropertyName = "C1";
    c1.DataSource = comboSource1;

    var c2 = new DataGridViewComboBoxColumn();
    c2.Name = "C2";
    c2.DataPropertyName = "C2";
    c2.DataSource = comboSource2;

    dataGridView1.Columns.AddRange(c1, c2);

    this.dataGridView1.DataSource = dt;
    dataGridView1.EditingControlShowing += dataGridView1_EditingControlShowing;
    dataGridView1.EditMode = DataGridViewEditMode.EditOnEnter;
}
private void dataGridView1_EditingControlShowing(object sender,
    DataGridViewEditingControlShowingEventArgs e)
{
    var dataGridView = sender as DataGridView;
    if (dataGridView?.CurrentCell?.ColumnIndex != 1) return;
    var comboBox = e.Control as DataGridViewComboBoxEditingControl;

    if (comboBox == null) return;
    comboBox.DropDownStyle = ComboBoxStyle.DropDown;
    if (!true.Equals(comboBox.Tag))
    {
        comboBox.Tag = true;
        comboBox.Validating += (obj, args) =>
        {
            var column = (DataGridViewComboBoxColumn)dataGridView.CurrentCell.OwningColumn;
            var list = comboBox.DataSource as List<string>;
            if (list == null) return;
            var txt = comboBox.Text;
            if (!list.Contains(txt))
            {
                list.Add(txt);
                column.DataSource = null;
                column.DataSource = list;
            }
            dataGridView.CurrentCell.Value = txt;
            dataGridView.NotifyCurrentCellDirty(true);
        };
    }
}
...