C# Winforms фильтрует представление данных из динамически созданных элементов управления - PullRequest
0 голосов
/ 25 апреля 2020

Я создаю базовый Form класс, в котором я создаю стиль по умолчанию, панели по умолчанию, сетку данных и панели инструментов. Когда я создаю новую специфицированную c форму, я расширяю этот базовый абстрактный класс, и новый класс автоматически имеет панель инструментов, сетку данных и фильтр. В новой форме я просто передаю источник данных datagridview, и у меня есть полный результат для всех моих форм. Я не трачу время на создание новых панелей, новых панелей инструментов, новых стилей и т. Д. c ....

Так что все эти проблемы начинаются с фильтрации сетки:

Когда я создаю сетку, я также создать элементы управления для фильтрации данных в сетке на основе столбцов сетки. Таким образом, я получаю выборки столбцов и на основе типа столбца сетки, который я генерирую в элементе управления боковой панели и надписи для этого столбца.

Вот код, как генерировать элементы управления на основе столбцов сетки:

   public void InitializeDefaultDataGridViewFilter()
    {
        int i = 0;

        foreach (DataGridViewColumn col in _dataGridView.Columns)
        {
            i++;

           // RowStyle temp = _tableLayout.RowStyles[_tableLayout.RowCount - 1];
            _tableLayout.RowCount++;
            _tableLayout.RowStyles.Add(new RowStyle(SizeType.AutoSize));

            _tableLayout.Controls.Add(new Label() { Text = col.HeaderText, TextAlign = System.Drawing.ContentAlignment.MiddleRight }, 0, _tableLayout.RowCount - 1);

            if (col is DataGridViewTextBoxColumn)
            {
                TextBox textBox = new TextBox()
                {
                    Dock = DockStyle.Fill,
                    Name = col.Name
                };

                _tableLayout.Controls.Add(textBox, 1, _tableLayout.RowCount - 1);
            }

            else if (col is DataGridViewCheckBoxColumn)
            {
                CheckBox checkBox = new CheckBox()
                {
                    Name = col.Name,
                    CheckState = CheckState.Checked
                };
                _tableLayout.Controls.Add(checkBox, 1, _tableLayout.RowCount - 1);
            }
            else
            {

            }
        }
    }

И я также создаю Button, который я поместил ниже фильтра и создаю событие

private void filterButton_Click(object sender, EventArgs e)
{
   // here now i need to filter
}

Теперь возникает проблема: как теперь узнать, какие элементы управления заполнены? ID, имя, PIB ... Et c? Как определить, какие элементы управления имеют значение, а какие элементы управления используют значение для фильтрации сетки.

Я знаю, как фильтровать сетку, но я не знаю, как определить, какие элементы управления Dynami c имеют значение и какой элемент управления используется для фильтрации указанных c столбец в сетке.

Если динамическое c текстовое поле для ID имеет значение 1232 сетка фильтра для этого столбца.

1 Ответ

1 голос
/ 26 апреля 2020

Как прокомментировали другие, это может быть лучшим подходом, чтобы получить «типы» столбцов из источника данных, который используется сеткой вместо самой сетки, а также создать «коллекцию» элементов управления, используемых для «фильтрации» сетки .

Можно набрать oop через _tableLayout.Controls и собрать элементы управления, которые необходимо отфильтровать, однако, «просматривая ВСЕ элементы управления» каждый раз, когда пользователь «фильтрует» данные, появляются не нужны, поскольку элементы управления не меняются при каждой операции фильтра. Следовательно, предлагается Control «сбор», чтобы избежать этой ненужной работы.

Кроме того, не совсем ясно, «как» вы хотите «фильтровать» сетку. Например, рисунок показывает каждый столбец слева, где пользователь может ввести текст, чтобы «отфильтровать» сетку по значению (ям), введенным в текстовые поля. Я предполагаю, что если пользователь вводит текст в два (2) или более текстовых поля, тогда фильтр будет использовать выражение «И» для фильтрации всех значений, введенных пользователем.

This « Фильтры типа «И», «ИЛИ» не ясны, кроме того, «фильтрация» в элементе управления «1009 *« флажок »может представлять проблему в том смысле, что она может вводить пользователя в заблуждение и определенно потребует больше работы над вашим часть. Например, для текстовых полей пользователю просто «сбросить» фильтр на «ничего», «очистив» текст в текстовом поле и снова нажав кнопку «фильтр».

Однако это не относится к флажку. Пользователь не может «очистить» «проверено \ не проверено» значение. Флажок либо «отмечен», либо нет, даже если вы установите для него какое-либо «три» состояние, как бы пользователь «визуально» увидел этот «очищенный» флажок?

Учитывая это, когда данные «Изначально» загружен И «до» применен любой «фильтр», ОБА, проверенные и непроверенные значения «Статус» будут отображаться пользователю. Однако после применения фильтра FIRST пользователь НИКОГДА не сможет «увидеть» ОБА проверенные и не проверенные значения «Status» снова без какого-либо «сигнала», указывающего на то, что они хотят «игнорировать» значение «Status». В приведенном ниже примере добавлена ​​кнопка для «сброса» сетки в исходное состояние.

Пример ниже начинается с двух глобальных переменных: GridTable и AllControls

private DataTable GridTable;
private Dictionary<Control, Type> AllControls;

Предоставление доступа к сетке источника данных GridTable - сохранение копии исходных данных, а также используется при настройке фильтра. Каждый раз, когда применяется новый фильтр, код использует эту таблицу для первоначальной установки «фильтра». Кроме того, словарь AllControls заполняется с использованием этой таблицы.

AllControls Dictionary используется в качестве «набора» элементов управления фильтра вместе со значением «Тип» элемента управления. Имейте в виду, что не обязательно иметь это значение «Тип», поскольку код ВСЕГДА использует одни и те же выражения фильтра «И» и «РАВНО» («=»), однако, если вы хотите фильтровать «частичное или содержащее» строковое значение с использованием ключевого слова «LIKE», тогда мы бы ДОЛЖНЫ различать guish «тип», чтобы убедиться, что мы не используем ключевое слово «LIKE» в столбце «числовой», так как оно будет sh. То же относится и к столбцам флажков.

Поскольку словарь отслеживает «тип» значения, удобно использовать это значение, чтобы определить, какой тип элемента управления использовать, то есть текстовое поле для strings, а также цифры и флажок для booleans.

В этом примере изначально в сетке используется DataTable в качестве DataSource. Когда применяется фильтр, DataView создается из исходной таблицы данных, затем к этому DataView применяется фильтр, и он используется как DataSource для сетки.

Как только мы получим сетки DataTable, мы можем использовать его для создания AllControls Dictionary. Здесь можно oop просмотреть столбцы таблицы, чтобы получить имя столбца, а также тип столбца. Для столбцов типа string и Numberri c мы добавляем в словарь TextBox и его тип значения (string / int). Для логических столбцов мы добавляем CheckBox в словарь. Поэтому метод GetControlsDictionary, который принимает GridTable и возвращает Dictionary<Control, Type>, может пригодиться и выглядеть следующим образом…

private Dictionary<Control, Type> GetControlsDictionary(DataTable dt) {
  Dictionary<Control, Type> controls = new Dictionary<Control, Type>();
  Control theControl;
  Type valueType;
  foreach (DataColumn col in dt.Columns) {
    valueType = col.DataType;
    switch (valueType.ToString()) {
      case "System.Int32":
      case "System.String":
        theControl = new TextBox() {
          Dock = DockStyle.Fill,
          Name = col.ColumnName
        };
        break;
      case "System.Boolean":
        theControl = new CheckBox() {
          Name = col.ColumnName,
          CheckState = CheckState.Unchecked
        };
        break;
      default:
        theControl = new TextBox() {
          Dock = DockStyle.Fill,
          Name = col.ColumnName
        };
        break;
    }
    controls.Add(theControl, valueType);
  }
  return controls;
}

С помощью словаря AllControls мы можем создать метод SetFilterControls, который берет словарь и устанавливает текстовые поля фильтра, et c. В приведенном ниже коде используется элемент управления TableLayoutPanel, как и в исходном коде, и он может выглядеть примерно так….

public void SetFilterControls(Dictionary<Control, Type> controls) {
  int rowIndex = 1;
  foreach (KeyValuePair<Control, Type> controlItem in controls) {
    _tableLayout.RowStyles.Add(new RowStyle(SizeType.AutoSize));
    _tableLayout.Controls.Add(new Label() { Text = controlItem.Key.Name, TextAlign = ContentAlignment.MiddleRight }, 0, rowIndex);
    _tableLayout.Controls.Add(controlItem.Key, 1, rowIndex++);
  }
}

Словарь AllControls также пригодится, когда мы захотим применить фильтр к сетка. Построение строки фильтра потребует, чтобы мы провели oop через словарь, проверили значение каждого элемента управления, а затем добавили это значение в строку фильтра. Например, если пользователь вводит «5» в поле фильтра «ID», а затем нажимает кнопку фильтра, строка фильтра будет выглядеть как… «[ID] = '5'». Если в текстовом поле более одного фильтра есть текст, это создаст составную строку фильтра «И». Например, если пользователь вводит «5» в текстовом поле «ID» И вводит «123» в текстовом поле «PIB», то строка фильтра будет выглядеть как… «[ID] = '5' AND [PIB] = «123». Если пользователь вводит нечисловые символы c в текстовое поле, соответствующее столбцу числового значения c, возвращается пустая строка. Кроме того, если какое-либо текстовое поле пусто, возвращается пустая строка. Этот GetFilterString() метод, который проходит по словарю, может выглядеть примерно так: Следует отметить, что здесь может потребоваться дополнительная проверка ошибок.

private string GetItemFilterString(KeyValuePair<Control, Type> item) {
  switch (item.Value.ToString()) {
    case "System.Int32":
      // if the text is NOT a valid int... then an empty string is returned
      if (String.IsNullOrEmpty(item.Key.Text) || (!int.TryParse(item.Key.Text, out int value))) {
        return "";
      }
      return "[" + item.Key.Name + "] = '" + item.Key.Text + "'";
    case "System.String":
      if (String.IsNullOrEmpty(item.Key.Text)) {
        return "";
      }
      return "[" + item.Key.Name + "] = '" + item.Key.Text + "'";
    case "System.Boolean":
      if (((CheckBox)item.Key).Checked) {
        return "[" + item.Key.Name + "] = True";
      }
      return "[" + item.Key.Name + "] = False";
    default:
      return "";
  }
}

Затем кнопка фильтра щелкает событие, чтобы использовать вышеуказанный метод (ы), и фильтрует сетку…

private void button1_Click(object sender, EventArgs e) {
  DataView dv = new DataView(GridTable);
  dv.RowFilter = GetFilterString();
  dataGridView1.DataSource = dv;
}

Как упоминалось ранее, я добавил еще одну кнопку для сброса данные возвращаются в нефильтрованное состояние.

private void button2_Click(object sender, EventArgs e) {
  dataGridView1.DataSource = GridTable;
}

Соединение всего этого может выглядеть как….

private void Form1_Load(object sender, EventArgs e) {
  GridTable = GetDT();
  dataGridView1.DataSource = GridTable;
  AllControls = GetControlsDictionary(GridTable);
  SetFilterControls(AllControls);
}


private DataTable GetDT() {
  DataTable dt = new DataTable();
  dt.Columns.Add("ID", typeof(int));
  dt.Columns.Add("Name", typeof(string));
  dt.Columns.Add("PIB", typeof(int));
  dt.Columns.Add("Registration Number", typeof(int));
  dt.Columns.Add("Status", typeof(bool));
  FillTable(dt);
  return dt;
}

private void FillTable(DataTable dt) {
  Random rand = new Random();
  int pib;
  int reg;
  bool stat;
  for (int i = 1; i < 21; i++) {
    pib = rand.Next(0, 20);
    reg = rand.Next(0, 3);
    stat = rand.Next(2) == 1;
    dt.Rows.Add(i, "Name_" + i, pib, reg, stat);
  }
}

Надеюсь, что это имеет смысл и помогает.

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