Windows forms работа с таблицами

C#: Табличные компоненты Windows Forms и работа с ними

Табличное представление данных повсеместно используется в приложениях. В этой лекции рассмотрены основные приёмы работы со следующими компонентами:

  • DataGridView – табличный редактор для отображения данных из файла XML или из БД (доступен в группе «Данные» Панели Элементов);
  • DataGrid – базовая табличная компонента для отображения связанных таблиц (щёлкнуть правой кнопкой мыши в Панели Элементов, команда «Выбрать элементы», дождаться загрузки списка, на вкладке «Компоненты .NET Framework» включить DataGrid из пространства имён System.Windows.Forms. После этого DataGrid можно добавить на форму).

Проект Lab4_1. Напишем простейший проект для редактирования таблицы и сохранения её в формате XML.

На форму добавим dataGridView1, установив ему свойство Dock = Fill, а объекты DataTable и DataSet создадим программно.

Для этого опишем глобально в классе формы следующие величины:

  private String BaseName;
  private DataTable Table;
  private DataSet Set;

На загрузку формы реализуем такой код (обработчик события Load):

   BaseName = "table.xml";
   Table = new DataTable ();
   Set = new DataSet ();
   if (System.IO.File.Exists (BaseName) == false) {
    //Если файл не существует - создать таблицу и DataSet
    dataGridView1.DataSource = Table;
    Table.Columns.Add ("Имена");
    Table.Columns.Add ("Номера телефонов");
    Set.Tables.Add (Table);
   }
   else {
    //Если файл существует - загрузить и показать данные
    Set.ReadXml (BaseName);
    String StringXML = Set.GetXml ();
    dataGridView1.DataMember = "Название таблицы";
    dataGridView1.DataSource = Set;
   }

Перед закрытием формы выполним следующий код (обработчик события FormClosing):

   Table.TableName = "Название таблицы";
   Set.WriteXml (BaseName);

Данные сохраняются в формате XML, после выполнения приложения найдите файл данных в папке с исполняемым файлом проекта.

Объект DataSet представляет собой кэш данных, расположенный в оперативной памяти. DataSet состоит из коллекции объектов класса DataTable.

Доступ к ячейкам таблицы можно получить, используя свойства класса DataTable (Rows, Cols, Item) — но «прямая» запись поля таблицы в файл может быть некорректной из-за того, что технология ADO.NET предусматривает кэширование данных (особенно если данные сохраняются посредством SQL-транзакций).
Пример такого кода:

   System.Data.DataRow newRow = Table.NewRow ();
   Table.Rows.Add (newRow);

Поэтому следует пользоваться методами объекта DataSet.

 Скачать пример Lab4_1 в архиве .zip с проектом C# Visual Studio 2019 (11 Кб)

Проект Lab4_2. Напишем простой проект для редактирования связанных отношением «один ко многим» таблиц.

Компонента DataGrid — решение для показа связанных таблиц в одной компоненте, в DataGridView такой возможности нет. Разместим компонент на форме, можно установить свойство Dock = Fill. Также предусмотрим пункты или кнопки меню «Переключить вид», «Сохранить», «Загрузить».

Эти данные описаны глобально в классе формы:

  private Boolean ShowClients; //Флажок-переключатель таблиц
  private System.Data.DataSet dataSet1; //Кэш данных
  private System.Data.DataTable Table, Table2; //Родительская и дочерняя таблицы

На загрузку формы (в обработчике её события Load) будем выполнять следующий код:

   ShowClients = true;
   if (System.IO.File.Exists ("data.xml") == true) {
    //Если файл существует - загрузить и показать данные
    загрузитьToolStripMenuItem_Click (this, e); //Обработчик команды "Загрузить"!
   }
   else { //Иначе создать предустановленные данные
    //Создадим таблицу:
    Table = new DataTable ("Клиенты");
    //Создадим и настроим столбец программно:
    DataColumn Column = new DataColumn ("Название организации");
    Column.ReadOnly = true;
    Column.Unique = true;
    Table.Columns.Add (Column);
    //Добавим столбцы с настройками по умолчанию, указав только названия:
    Table.Columns.Add ("Контактное лицо");
    Table.Columns.Add ("Телефон");
    //Создадим DataSet и добавим туда таблицу:
    dataSet1 = new DataSet ();
    dataSet1.Tables.Add (Table);
    //Добавим в таблицу предустановленные записи об организациях-заказчиках
    Table.Rows.Add ("НГАСУ", "Иванов Максим", "3234566");
    Table.Rows.Add ("НГТУ", "Сидорова Ксения", "3630313");
    //Создадим вторую таблицу - "Заказы"
    Table2 = new DataTable ("Заказы");
    DataColumn Column2 = new DataColumn ("Номер заказа");
    Column2.DataType = System.Type.GetType ("System.Int32");
    Column2.AutoIncrement = true; //Автоматический счётчик заказов
    Column2.ReadOnly = true; Column2.Unique = true; //Название организации - уникально!
    Table2.Columns.Add (Column2);
    Table2.Columns.Add ("Объем заказа");
    Table2.Columns.Add ("Организация-заказчик");
    //Добавим в DataSet вторую таблицу:
    dataSet1.Tables.Add (Table2);
    Table2.Rows.Add (1, "100000", "НГАСУ");
    Table2.Rows.Add (2, "200000", "НГАСУ");
    //Обеспечим отношение 1:N между первой и второй таблицами:
    DataColumn Parent = dataSet1.Tables ["Клиенты"].Columns ["Название организации"];
    DataColumn Child = dataSet1.Tables ["Заказы"].Columns ["Организация-заказчик"];
    DataRelation Link1 = new DataRelation ("Ссылка на заказы клиента", Parent, Child);
    // В Parent значения в связываемом столбце должны быть уникальными, в Child - нет
    dataSet1.Tables ["Заказы"].ParentRelations.Add (Link1);
   }
   dataGrid1.SetDataBinding (dataSet1, "Клиенты");
   dataGrid1.CaptionText = "Родительская таблица \"Клиенты\"";
   dataGrid1.CaptionFont = new System.Drawing.Font ("Consolas", 11);

На нажатие кнопки или выбор пункта меню «Переключить вид» будем переключаться между родительской и дочерней таблицами:

   if (ShowClients == true) {
    dataGrid1.SetDataBinding (dataSet1, "Клиенты");
    dataGrid1.CaptionText = "Родительская таблица \"Клиенты\"";
   }
   else {
    dataGrid1.SetDataBinding (dataSet1, "Заказы");
    dataGrid1.CaptionText = "Дочерняя таблица \"Заказы\"";
   }
   dataGrid1.Collapse (-1); //Свернуть все ветви
   ShowClients = !ShowClients;

На выбор команды «Сохранить» будем сохранять все данные в файле типа .xml текущей папки:

   dataSet1.WriteXml ("data.xml", XmlWriteMode.WriteSchema);

На выбор команды «Загрузить» будем обновлять все данные из файла, сбросив несохранённые изменения, если таковые есть:

   dataSet1 = new DataSet ();
   dataSet1.ReadXml ("data.xml");
   ShowClients = true;
   переключитьВидToolStripMenuItem_Click (this, e);

Приложение запускается и редактирует связанные таблицы.

 Скачать пример Lab4_2 в архиве .zip с проектом C# Visual Studio 2019 (12 Кб)

Проект Lab4_3. Реализуем больше возможностей компоненты DataGridView. Форма приложения будет такой же, как в проекте 4.1, а действия можно запрограммировать как реакцию на выбор пунктов верхнего меню.

Она представляет собой прямоугольный массив ячеек, который можно рассматривать как коллекцию строк или столбцов.

  • Rows — это коллекция строк, имеет тип DataGridRowCollection.
  • Columns — это коллекция столбцов типа DataGridColumnCollection.
    Оба свойства индексируются как массивы для доступа к конкретной строке/столбцу, нумерация производится с нуля.
  • Cells — это коллекция ячеек из объекта DataGridRowCollection, приведём пример доступа к конкретной ячейке:
    try {
        MessageBox.Show (dataGridView1.Rows [1].Cells [1].Value.ToString ());
       }
       catch (Exception) { MessageBox.Show ("Нет такой ячейки"); }
  • RowCount, ColumnCount — количество строк и столбцов.

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

Методы для добавления/удаления/редактирования строк и столбцов относятся к коллекциям Rows и Columns и имеют типовые имена: Add, Insert, Clear, AddCopy, InsertCopy, Remove, RemoveAt, а также могут иметь по несколько перегрузок каждая, например, для метода Add добавления строки есть версии Add(), Add(int count), Add (DataGridViewRow row), Add (object []values).

  private static int Cnt; //Счётчик столбцов в классе формы
  //...	

   if (dataGridView1.ColumnCount < 1) { //Сначала нужно создать столбец
    dataGridView1.Columns.Add ("Столбец " + Cnt, "Заголовок " + Cnt);
    Cnt++;
   }
   dataGridView1.Rows.Add ();

Настройка внешнего вида компонента также типовая: такие свойства, как BackColor, Alignment, Font и т.д. находятся в объекте типа DataGridViewCellStyle.

Каждая ячейка представлена объектом System.Windows.Forms.DataViewCell, за «личный» внешний вид ячейки отвечает свойство InheritedStyle, а за вид по умолчанию — DefaultCellStyle.

Очередной командой перекрасим фон таблицы в розовый цвет:

   dataGridView1.DefaultCellStyle.BackColor = Color.Pink;

А теперь поменяем фон только выбранной ячейки:

   if (cell_y > -1 && cell_x > -1)
    dataGridView1.Rows[cell_y].Cells[cell_x].Style.BackColor = Color.Green;

Предполагается, что значения cell_y, cell_x описаны глобально в классе формы:

   private int cell_y, cell_x;

и инициализируются в обработчике её события Load:

   cell_y = cell_x = -1;

а затем получают значения в обработчиках событий KeyUp и MouseUp компоненты dataGridView1 (одинаковым кодом):

   cell_y = dataGridView1.CurrentCell.RowIndex;
   cell_x = dataGridView1.CurrentCell.ColumnIndex;

Когда требуется форматирование содержимого ячейки DataGridView для отображения, возникает событие CellFormatting, вот пример его обработчика:

   e.CellStyle.SelectionBackColor = Color.Yellow;
   e.CellStyle.SelectionForeColor = Color.Black;

Сделаем в dataGridView1 таблицу со значениями функции. Вот код соответствующей команды:

   dataGridView1.Columns.Clear ();
   dataGridView1.ColumnCount = 2;
   dataGridView1.Rows.Add (10); //Добавили 10 строк
   dataGridView1.Columns [0].Name = "X";
   dataGridView1.Columns [1].Name = "Y(X)";
   double x; int i;
   for (x = 1.5, i = 0; i < 10; x += 0.1, i++) {
    dataGridView1.Rows [i].Cells [0].Value = Convert.ToString (x);
    dataGridView1.Rows [i].Cells [1].Value = Math.Round (x * x, 2).ToString ();
    //или dataGridView1.Rows[i].Cells[1].Value = (x*x).ToString("f");
   }

Существует также множество событий, связанных с редактированием ячейки: CellBeginEdit, CellEndEdit, CellParsing, CellValidating, CellValidated и т.д.

Например, по умолчанию наша таблица редактируется. Чтобы разрешить в первом столбце (Y(X)) ввод только числовых значений, напишем следующий код, выполняемый по событию CellValueChanged компоненты DataGridView:

   String Val =
    dataGridView1.Rows[e.RowIndex].Cells[e.ColumnIndex].Value.ToString ();
   if (e.ColumnIndex == 1) {
    double val;
    bool A = Double.TryParse (Val,
     System.Globalization.NumberStyles.Number,
     System.Globalization.NumberFormatInfo.CurrentInfo, out val);
    if (A == false) {
     dataGridView1.Rows[e.RowIndex].Cells [e.ColumnIndex].Value = lastValue;
     MessageBox.Show ("Неверное число: " + Val, "Ошибка");
    }
   }

Здесь предполагается, что величина lastValue описана в классе формы:

  private double lastValue;

и по событию CellBeginEdit, сохраняет предыдущее значение, хранимое в ячейке:

   if (e.ColumnIndex == 1) lastValue =
    Convert.ToDouble (dataGridView1.Rows[e.RowIndex].Cells[e.ColumnIndex].Value);

Запретить редактирование данных можно стандартно – с помощью свойства ReadOnly. Чтобы запретить редактирование конкретной ячейки, строки или столбца, также воспользуйтесь этим свойством:

   if (dataGridView1.ColumnCount > 0) {
    dataGridView1.Rows [0].Cells [0].ReadOnly = true;
    dataGridView1.Columns [0].ReadOnly = true;
   }

 Скачать пример Lab4_3 в архиве .zip с проектом C# Visual Studio 2019 (12 Кб)

Проект Lab4_4. Пример выполнения варианта задания. Написать табличный редактор ведомости студенческой группы со столбцами: Фамилия, 1, 2, …, 17 (номера недель), итого (отметка о зачете)

Данные автоматически загружаются из файла и сохраняются в файле формата xml.

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

Первый вариант решения — создать таблицу dataGridView, не связанную с DataSet и работать непосредственно с ячейками через методы класса dataGridView. Сложности такого подхода – придётся «вручную» писать поддержку сохранения и загрузки таблицы.
Второй вариант – связать таблицу с DataSet, чтобы легко загружать и сохранять данные XML, но тогда работа с добавлением/удалением ячеек делается через методы кэша DataSet, иначе компилятор и не разрешит выполнять этого.

Создав новый проект Windows Forms с главной формой Form1, добавим на неё компоненту DataGridView и растянем на всю форму (свойство Dock = Fill). Также добавим к проекту контекстное меню contextMenuStrip с пунктами «Добавить», «Удалить», «Вычислить» и укажем его в свойстве ContextMenuStrip компоненты dataGridView1.

Пропишем в классе формы глобальные величины:

  private String BaseName;
  private DataTable  Table;
  private DataSet Set;
  private String Val; //предыдущее значение из текущей ячейки
  private int Column; //текущий столбец
  private bool Changed; //признак изменения текущей ячейки

Столбцы таблицы (фамилия, 17 граф для оценок или иных отметок, графа «зачёт») создадим программно по событию Load формы:

   BaseName = "table.xml"; 
   Table = new DataTable (); 
   Set = new DataSet ();
   dataGridView1.DataSource = Table;
   Table.Columns.Add ("ФИО");
   for (int i = 1; i <= 17; i++) Table.Columns.Add ("" + i);
   Table.Columns.Add ("Итого");
   Set.Tables.Add (Table); 
   dataGridView1.DataSource = Set;
   Table.TableName = "Успеваемость";
   if (System.IO.File.Exists (BaseName) == true) {
    Set.ReadXml (BaseName);
   }
   dataGridView1.DataMember = "Успеваемость";
   dataGridView1.Columns [0].Width = 100;
   for (int i = 1; i <= 17; i++) dataGridView1.Columns [i].Width = 25;

«Подогнать» ширину столбцов под ширину формы можно, например, в обработчике события SizeChanged формы (при старте приложения ширина «подогнана» не будет):

   Rectangle Rect = this.ClientRectangle;
   int w = Rect.Width; //клиентская ширина формы
   if (w < 400) w = Rect.Width = 400;
   int border = dataGridView1.Columns [0].DividerWidth,
    left = dataGridView1.Rows [0].HeaderCell.Size.Width;
   //ширина разделителя столбцов и закрепленного столбца слева
   int w1 = 100,
       w2 = (int) Math.Floor (( w - 2 * w1 - 19 * border - left ) / 17.0);
   //под 1-й и последний столбец по 100 пикселей, остальное место делим поровну
   dataGridView1.Columns [0].Width = dataGridView1.Columns [18].Width = w1;
   for (int i = 1; i <= 17; i++) dataGridView1.Columns [i].Width = w2;

Также будем автоматически сохранять данные при выходе из программы (событие формы FormClosing):

   Table.TableName = "Успеваемость";
   Set.WriteXml (BaseName);

По выбору пункта меню «Добавить» выполняется следующее:

   DataRow newR = Set.Tables ["Успеваемость"].NewRow ();
   newR [0] = "Студент";
   try {
    int i = dataGridView1.CurrentCell.RowIndex;
    Set.Tables ["Успеваемость"].Rows.InsertAt (newR, i);
    Set.Tables ["Успеваемость"].AcceptChanges ();
   }
   catch (Exception) { }

А пункт «Удалить» проще всего запрограммировать так:

   try {
    int i = dataGridView1.CurrentCell.RowIndex;
    Set.Tables ["Успеваемость"].Rows [i].Delete ();
    Set.Tables ["Успеваемость"].AcceptChanges ();
   }
   catch (Exception) { }

Применение метода AcceptChanges нужно, чтобы изменение данных немедленно отобразилось в таблице.

Контроль правильности ввода (не более 1 символа в графы отметок, не более 20 символов в графы «ФИО» и «Итого») сделаем следующими обработчиками событий компоненты dataGridView1:

CellBeginEdit(на начало редактирования):

   Column = e.ColumnIndex; //запоминаем  столбец
   Val = dataGridView1.Rows[e.RowIndex].Cells[e.ColumnIndex].Value.ToString ();
    //что было в ячейке
   Changed = false; //ячейка не изменена

CellValueChanged (по изменению ячейки):

   String newVal =
    dataGridView1.Rows[e.RowIndex].Cells[e.ColumnIndex].Value.ToString ();
   if (e.ColumnIndex > 0 && e.ColumnIndex < 18) {
    if (newVal.Length > 1) newVal = Val;
   }
   else if (newVal.Length > 20) newVal = newVal.Substring(0,20);
   dataGridView1.Rows[e.RowIndex].Cells [e.ColumnIndex].Value = newVal;

EditingControlShowing (для установки своих обработчиков в дополнение к стандартным обработчиками событий компоненты):

   if (Column > 0 && Column < 18) {
    TextBox tb = (TextBox)e.Control;
    tb.MaxLength = 1;
    tb.KeyPress += new KeyPressEventHandler (tb_KeyPress);
   }

В проект добавлен метод tb_KeyPress – дополнение к обработке KeyPress, разрешающее вводить буквы, цифры, Backspace и пробел:

  void tb_KeyPress (object sender, KeyPressEventArgs e) {
   char c = e.KeyChar;
   if (!( Char.IsLetterOrDigit (c) || c == (char) Keys.Back || 
     c == (char) Keys.Space )) e.Handled = true;
   //а вот обработчик KeyDown так не сделать
  }

CellLeave (покидая ячейку, изменим правила перехода к следующей ячейке, по умолчанию это вниз, а мы хотим вправо):

   //конечно, "костыль", по идее, надо писать класс-наследник 
   //DataGridView и там управлять клавиатурой
   if (!Changed) {
    Changed = true;
    int c = dataGridView1.CurrentCell.ColumnIndex;
    if (c == dataGridView1.Columns.Count - 1) {
     SendKeys.Send ("{Home}");
    }
    else {
     SendKeys.Send ("{Up}");
     SendKeys.Send ("{Right}");
    }
   }

Проблема состоит в том, что DataGridView обрабатывает многие клавиши своими собственными событиями и «не пускает» коды до уровня KeyPress или KeyDown (KeyUp выполняется).

Как пример расчёта добавим вычисление среднего балла по выставленным отметкам, код можно выполнить по соответствующему пункту меню:

   for (int i = 0; i < dataGridView1.RowCount - 1; i++) {
    int sum = 0, cnt = 0, val = 0;
    for (int j = 1; j < dataGridView1.ColumnCount - 1; j++) {
     String str = dataGridView1.Rows [i].Cells [j].Value.ToString ().Trim();
     try {
      if (str.Length > 0) val = Int32.Parse (str);
      else continue;
     }
     catch (Exception) {
      continue;
     }
     sum += val;
     cnt++;
    }
    if (cnt > 0) {
     double avg = (sum + 0.0) / cnt; //чтобы результат был double
     dataGridView1.Rows [i].Cells [dataGridView1.ColumnCount - 1].Value =
      String.Format ("{0:f2}", avg);
    }
   }

Мы выбираем для обработки только оценки (не проверяя их корректность), так как в ведомости могли быть другие отметки, например «б» (болен), «н» (отсутствует) и т.п.

Границей внешнего цикла, равной dataGridView1.RowCount — 1, мы исключаем при обработке пустую строку в конце таблицы, не содержащую данных.

 Скачать пример Lab4_4 в архиве .zip с проектом C# Visual Studio 2019 (13 Кб)

Задание: реализовать табличный редактор в соответствии с вариантом задания. Предусмотреть в приложении следующие возможности:

  • загрузка табличных данных из файла и их сохранение в файл;
  • редактирование, добавление, удаление записей;
  • при необходимости – поиск и выделение (или отображение в новом окне) записей, отвечающих заданным условиям;
  • реализация расчётов, указанных в варианте задания.

09.03.2023, 10:49 [1279 просмотров]


К этой статье пока нет комментариев, Ваш будет первым

Время на прочтение
6 мин

Количество просмотров 22K

Доброго времени суток!

В данной статье я опишу создания своих элементов для C# Windows Form.

Для примера буду создавать таблицу со всем функционалом DataGridView. Позже перейдем на свои элементы. Создание первого элемента разобьем на несколько уроков. В данном уроке произведем от рисовку таблицы, а также: создание столбцов, строк, ячеек.

Для написания будем использовать .Net FrameWork 4.7.x, среда разработки Visual Studio 2019.

В первую очередь создадим обычный проект Windows Form. Думаю не нужно это показывать. А уже потом создаем проект «Библиотека элементов управления Windows Form»(Назовем его CustomControl).

Далее у нас будет создан файл UserControl.cs. Удаляем его и создаем обычный класс TableCustoms.cs.Наш класс будет наследоваться от класса Control.

Далее в этом же файле создадим еще несколько классов, а именно:Column,Row,Cell. Рассмотрим каждый по отдельности. Начнем с Column:

    [Serializable]
    public class Column
    {
        public string Name { get; set; } = "NameColumn";//Наименование Столбца 
        public string Caption { get; set; } = "CaptionColumn";//Текст заголовка
        public int Width { get; set; } = 100;//Стандартная ширина
        public Color Back { get; set; } = Color.White;//Цвет фона
        
        public Column()
        { 
        
        }
    }

Класс Row:

    [Serializable]
    public class Row
    {
        public int Heigth { get; set; } = 20;// Высота строки
        public List<Cell> Cells { get; set; } = new List<Cell>();//список ячеек
        public Row()
        {
 
        }
        public Row(List<Cell> cells)
        {
            Cells = cells;
        }

    }

Класс Cell(Для поддержки копирования добавляем интерфейс ICloneable):

    [Serializable]
    public class Cell : ICloneable
    {
        public object Value { get; set; } = null;//значение ячейки 
        public Cell()
        {
        }
        public object Clone()
        {
            return MemberwiseClone();
        }
    }

Теперь настроим наш основной класс TableCustoms:

   public class TableCustoms : Control
    {
        #region Перемененные
        public ObservableCollection<Column> Columns { get; set; } = new ObservableCollection<Column>();//Список столбцов таблицы
        private ObservableCollection<Row> rows = new ObservableCollection<Row>();//Список строк
        private int countRow = 0;//количество строк
        #endregion
        #region Свойства
        public int CountRow // гетер и сетер при увеличении переменной на N раз
        {
            get { return countRow; }
            set
            {
                //При увеличении добавляем 
                if (value > countRow)
                {
                    int iteration = value - countRow;
                    for (int i = 0; i < iteration; i++)
                    {
                        rows.Add(new Row());
                    }
                }
                //при уменьшении удаляем с конца
                if (value < countRow)
                {
                    int iteration = countRow - value;
                    for (int i = 0; i < iteration; i++)
                    {
                        rows.Remove(rows[rows.Count - 1]);
                    }
                }

                countRow = value;
            }
        }
        //гетер и сетер для списка строк, будет использоваться позже
        public ObservableCollection<Row> Rows
        {
            get { return rows; }
            set { }
        }

        public int ColumnHeaderHeigth { get; set; } = 20;//высота шапки таблицы
        public int RowHeaderWidth { get; set; } = 20;//высота заголовков строк
        public Color ColumnHeaderBack { get; set; } = SystemColors.Control;//Основной цвет фона заголовков таблицы
        public Color BorderColor { get; set; } = Color.Black;//Стандартный цвет границ таблицы
        public bool NumerableRows { get; set; } = false;//Флаг автоматической нумерации
        #endregion
        //Метода изменения столбцов, будет использоваться в следующем уроке
        private void EditColumn()
        {

        }
        //Метод изменения строк
        private void EditRows()
        {
            if (countRow < rows.Count)//Увеличение количества строк
            {
                rows[rows.Count - 1].Cells = CreatCells(Columns.Count);//Добавление пустых ячеек в строку
                countRow++;
            }
            if (CountRow > rows.Count)//уменьшение количества строк
            {
                countRow--;
            }

        }
        //метод создания N количества ячеек
        private List<Cell> CreatCells(int Count)
        {
            // return Enumerable.Repeat(new Cell(), Count).ToList();
            List<Cell> result = new List<Cell>();
            for (int i = 0; i < Count; i++)
            {
                result.Add(new Cell());
            }
            return result;
        }
        public TableCustoms()
        {
            rows.CollectionChanged += (e, v) => EditRows();//проверка изменения списка
            Columns.CollectionChanged += (e, v) => EditColumn();//проверка изменения списка
            BackColor = SystemColors.AppWorkspace;//Стандартный фон
            PanelTable panelTable = new PanelTable(this);//Создание основной панели
            panelTable.Dock = DockStyle.Fill;//Растягиваем основную панель по Control
            Controls.Add(panelTable);//Добавление панели на Control
        }
    }

Для того, чтобы у нас были полосы прокрутки нужно использовать ScrollableControl, поэтому создадим класс PanelTable наследуем ScrollableControl и помещаем его на Control(в следующем уроке объясню почему создаем два разных контрола, а не используем сразу ScrollableControl):

 internal class PanelTable : ScrollableControl//Control со ScrolLbar
        {
            private TableCustoms BParent;//переменная основного класса, для работы с свойствами
            public PanelTable(TableCustoms bParent)
            {
                HScroll = true;//Отображение ползунка по горизонтали
                VScroll = true;//Отображение ползунка по вертикали
                AutoScroll = true;//Автоматическое появление полос прокрутки
                BParent = bParent;
            }
            //переопределение метода
            protected override void OnPaint(PaintEventArgs e)
            {
                Matrix m = new Matrix();
                m.Translate(this.AutoScrollPosition.X, this.AutoScrollPosition.Y, MatrixOrder.Append);
                e.Graphics.Transform = m;
                Graphics graf = e.Graphics;
                int maxWidth = 0;//Высота AutoScrollMinSize
                int maxHeight = 0;//Ширина AutoScrollMinSize
                                  //расчитываем ширину
                foreach (Column item in BParent.Columns)
                {
                    maxWidth += item.Width;
                }
                //расчитываем высоту
                foreach (Row item in BParent.Rows)
                {
                    maxHeight += item.Heigth;
                }
                AutoScrollMinSize = new Size(maxWidth + 100, maxHeight + 100);//назначаем AutoScrollMinSize относительно этого будут появляться полосы прокрутки
                graf.Clear(BParent.BackColor);
                DrawHeaderColumns(graf);//Отрисовка заголовков столбцов таблицы
                DrawHeaderRows(graf);//Отрисовка заголовков строк таблицы
                DrawCells(graf);//Отрисовка ячеек
                base.OnPaint(e);
            }
            /// <summary>
            /// Отрисока заголовков столбцов
            /// </summary>
            /// <param name="graf"></param>
            private void DrawHeaderColumns(Graphics graf)
            {
                int x = 2;
                Rectangle rect;
                rect = new Rectangle(x, 1, BParent.RowHeaderWidth, BParent.ColumnHeaderHeigth);
                graf.DrawRectangle(new Pen(BParent.BorderColor), rect);
                graf.FillRectangle(new SolidBrush(BParent.ColumnHeaderBack), rect);
                x += BParent.RowHeaderWidth + 1;
                foreach (Column item in BParent.Columns)
                {
                    rect = new Rectangle(x, 1, item.Width, BParent.ColumnHeaderHeigth);
                    graf.DrawRectangle(new Pen(BParent.BorderColor), rect);
                    graf.FillRectangle(new SolidBrush(BParent.ColumnHeaderBack), rect);
                    if (item.Caption.Length != 0)
                    {
                        StringFormat sf = new StringFormat();
                        sf.Alignment = StringAlignment.Center;
                        sf.LineAlignment = StringAlignment.Center;
                        graf.DrawString(item.Caption, new Font("Times", 9), Brushes.Black, rect, sf);
                    }
                    x += item.Width + 1;
                }
            }
            //Отрисовка заголовков строк
            private void DrawHeaderRows(Graphics graf)
            {
                int y = 1;
                int i = 0;
                Rectangle rect;
                y += BParent.RowHeaderWidth + 1;
                foreach (Row item in BParent.Rows)
                {
                    rect = new Rectangle(2, y, BParent.RowHeaderWidth, item.Heigth);
                    graf.DrawRectangle(new Pen(BParent.BorderColor), rect);
                    graf.FillRectangle(new SolidBrush(BParent.ColumnHeaderBack), rect);
                    if (BParent.NumerableRows)
                    {
                        StringFormat sf = new StringFormat();
                        sf.Alignment = StringAlignment.Center;
                        sf.LineAlignment = StringAlignment.Center;
                        graf.DrawString(i.ToString(), new Font("Times", 9), Brushes.Black, rect, sf);
                    }
                    i++;
                    y += item.Heigth + 1;
                }
            }
            //отрисовка ячеек
            private void DrawCells(Graphics graf)
            {

                int x = 2 + BParent.RowHeaderWidth + 1;
                int y = 2 + BParent.ColumnHeaderHeigth;
                Rectangle rect;
                int i = 0;
                foreach (Row itemRow in BParent.Rows)
                {
                    foreach (Column itemColumn in BParent.Columns)
                    {
                        rect = new Rectangle(x, y, itemColumn.Width, itemRow.Heigth);
                        graf.DrawRectangle(new Pen(BParent.BorderColor), rect);
                        graf.FillRectangle(new SolidBrush(Color.White), rect);
                        if (itemRow.Cells[i].Value != null)
                        {
                            StringFormat sf = new StringFormat();
                            sf.Alignment = StringAlignment.Center;
                            sf.LineAlignment = StringAlignment.Center;
                            graf.DrawString(itemRow.Cells[i].Value.ToString(), new Font("Times", 9), Brushes.Black, rect, sf);
                        }
                        x += itemColumn.Width + 1;
                        i++;
                    }
                    i = 0;
                    y += itemRow.Heigth + 1;
                    x = 2 + BParent.RowHeaderWidth + 1;
                }
            }
        }

После этого «Пересобираем проект» элемента и добавляем элемент на форму(в основном проекте):

image

Теперь проверим некоторые методы нашего элемента:

  public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
             tableCustoms1.Rows.Add(new Row());//добавление строки
             tableCustoms1.Rows.Add(new Row());
             tableCustoms1.Rows[0].Cells[0].Value = "1";//Изменение значения ячейки
             tableCustoms1.Rows[1].Cells[1].Value = "2";
            tableCustoms1.CountRow++;//увеличение числа строк
            tableCustoms1.Rows[0].Cells[0].Value = "привет";
        }
    }

Запускаем наш проект:

image

There is ALWAYS a way to get it to work. It may not be obvious from the WinForms designer, but it is not too hard.

Try this:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace WindowsFormsApplication1
{
  partial class Form_1:Form 
  {

    public Form_1()
    {
      InitializeComponent();

    }

    /// <summary>
    /// Required designer variable.
    /// </summary>
    private System.ComponentModel.IContainer components = null;

    /// <summary>
    /// Clean up any resources being used.
    /// </summary>
    /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
    protected override void Dispose(bool disposing)
    {
      if (disposing && (components != null))
      {
        components.Dispose();
      }
      base.Dispose(disposing);
    }

    private void InitializeComponent()
    {
      this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel();
      this.panel4 = new System.Windows.Forms.Panel();
      this.panel3 = new System.Windows.Forms.Panel();
      this.panel2 = new System.Windows.Forms.Panel();
      this.panel1 = new System.Windows.Forms.Panel();
      this.tableLayoutPanel1.SuspendLayout();
      this.SuspendLayout();
      // 
      // tableLayoutPanel1
      // 
      this.tableLayoutPanel1.ColumnCount = 2;
      this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 25F));
      this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 75F));
      this.tableLayoutPanel1.Controls.Add(this.panel4, 3, 0);
      this.tableLayoutPanel1.Controls.Add(this.panel3, 2, 0);
      this.tableLayoutPanel1.Controls.Add(this.panel2, 1, 0);
      this.tableLayoutPanel1.Controls.Add(this.panel1, 0, 0);
      this.tableLayoutPanel1.SetRowSpan(this.panel1, 3);//This line is the key!!!!!
      this.tableLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill;
      this.tableLayoutPanel1.Location = new System.Drawing.Point(0, 0);
      this.tableLayoutPanel1.Name = "tableLayoutPanel1";
      this.tableLayoutPanel1.RowCount = 3;
      this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 33.33333F));
      this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 33.33333F));
      this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 33.33333F));
      this.tableLayoutPanel1.Size = new System.Drawing.Size(527, 372);
      this.tableLayoutPanel1.TabIndex = 0;
      // 
      // panel4
      // 
      this.panel4.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
      this.panel4.Dock = System.Windows.Forms.DockStyle.Fill;
      this.panel4.Location = new System.Drawing.Point(134, 251);
      this.panel4.Name = "panel4";
      this.panel4.Size = new System.Drawing.Size(390, 118);
      this.panel4.TabIndex = 4;
      // 
      // panel3
      // 
      this.panel3.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
      this.panel3.Dock = System.Windows.Forms.DockStyle.Fill;
      this.panel3.Location = new System.Drawing.Point(134, 127);
      this.panel3.Name = "panel3";
      this.panel3.Size = new System.Drawing.Size(390, 118);
      this.panel3.TabIndex = 3;
      // 
      // panel2
      // 
      this.panel2.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
      this.panel2.Dock = System.Windows.Forms.DockStyle.Fill;
      this.panel2.Location = new System.Drawing.Point(134, 3);
      this.panel2.Name = "panel2";
      this.panel2.Size = new System.Drawing.Size(390, 118);
      this.panel2.TabIndex = 2;
      // 
      // panel1
      // 
      this.panel1.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
      this.panel1.Dock = System.Windows.Forms.DockStyle.Fill;
      this.panel1.Location = new System.Drawing.Point(3, 3);
      this.panel1.Name = "panel1";
      this.panel1.Size = new System.Drawing.Size(125, 366);
      this.panel1.TabIndex = 1;
      // 
      // Form1
      // 
      this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
      this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
      this.ClientSize = new System.Drawing.Size(527, 372);
      this.Controls.Add(this.tableLayoutPanel1);
      this.Name = "Form1";
      this.Text = "Form1";
      this.tableLayoutPanel1.ResumeLayout(false);
      this.ResumeLayout(false);

    }

    private System.Windows.Forms.TableLayoutPanel tableLayoutPanel1;
    private System.Windows.Forms.Panel panel1;
    private System.Windows.Forms.Panel panel3;
    private System.Windows.Forms.Panel panel2;
    private System.Windows.Forms.Panel panel4;
  }
}

The key to get this to work is this line:

this.tableLayoutPanel1.SetRowSpan(this.panel1, 3);//This line is the key!!!!!

November 2005

Objectives

  • To explain how to use Table layout engine to organize and order
    WinForms in tabular format

Contents

Introduction
Basics
Advanced operations with table
Creation of nested tables
Conclusion
Introduction

Did you find yourself wasting time in reordering controls while
designing user interface layout? Isn’t be much simple if you use table
(like table in Word, Excel or HTML table)? In this article I
will explain how to use the power of table layout engine
which is part of LidorSystems.Collector library.

Basics

To start working with table you need to insert Page control from the
toolbox on Form. After that, right click on the
Page to insert table. A dialog is shown in which
you enter basic parameters of the table, and a
new table object is created.

Table Layout Engine in Docking Windows, Tabbed documents and Table layout for WinForms

Page control can have only one table object present. Table consist of
cells ordered in columns and rows. Each cell can contain only
one control at a time, but you can move controls from one cell
to another with drag&drop.
Cells can be resized, merged, split to form another cells.
They have the ability to align their content in nine positions
and most important they can lock content position and size.
Content of cells can be control of any type that can be accepted
by the Form, including Collector controls.

To add controls to the table simply drop it from the toolbox to
the selected cell or copy/paste existing controls on your Form.
When control is added, cell automatically adjust the size to
the control size. This is because by default every cell has SizeType property
value set to AutoSize. This property can receive two more
values:
Fixed
and Free. Additionaly when you resize
cells, their content will also resize. To prevent cells from
resizing, SizeType

property value of column or row, in which cell belong, must be
set to Fixed.

Table Layout Engine in Docking Windows, Tabbed documents and Table layout for WinForms

For additional space you can insert columns or rows before or after
selected cell. Selection of cells can be done either from
the context menu by selection of columns or rows or with mouse
dragging. After some cells are selected they can align their content in nine
positions by setting their alignment type.

Table Layout Engine in Docking Windows, Tabbed documents and Table layout for WinForms

Advanced operations with table

The power of table lies in cells abillity to be resized, merged, splitted,
autosized to accomodate their content. This way  you can quickly and
easily adjust positions and size of your controls that maintain
persistent. Further more cell content can be locked with setting
the SizeType property
value to Fixed.

Some controls need more space and cannot be added only in one cell. To
create space for this controls first select some cells and then click
on the Merge
cells
item from the context menu. Sometimes you will need
to split cell to create additional cells. This can be done
by selecting the cell that you want to split and click
on the Split
cell
option
from the context menu, upon which you will be asked of whether
you want to split cell in number of rows or columns.

Table Layout Engine in Docking Windows, Tabbed documents and Table layout for WinForms

When you resize cells, if you feel that autosizing of controls is annoying
to you, change SizeType of cells to Free.
This way the size of controls will not be affected by resizing
operations and in each cell you can set control to occupy smaller
space of cell and further make control alignment to any side of the
cell.

When you are done with placement of controls to the table and you want
cells to have persistent size while changing the size of parent
Page control (in which table object is placed), from the properties
window expand the TableObject
property and set the AutoSize property value to True.
Further more lock rows or columns to prevent their cells from
resizing.

Creation of nested tables

Sometimes the desired layout cannot be arranged by using simple table
structure, even if there is merged or splitted cells. Solution
to this problem is in creation of nested tables within cells.

To create nested table, add Page control to selected cell. Then in this
page create table with custom number of columns and rows. Put
some controls to this table. This way you can manage tables
separatelly from one another, although they are nested.

Table Layout Engine in Docking Windows, Tabbed documents and Table layout for WinForms

Conclusion

Table layout engine through operations with each cell, row and
column gives you possiblity to quickly form, align and arrange WinForms
in tabular format in order to achieve the best look for your application. 

Windows Forms является одним из графических фреймворков, используемых для создания приложений в среде разработки Microsoft Visual Studio. Одним из важных элементов пользовательского интерфейса является таблица, которая позволяет отображать и организовывать данные в удобной форме. Ниже рассмотрены основные шаги по созданию таблицы на Windows Forms и использованию ее функциональности.

Первым шагом является создание нового проекта Windows Forms в Visual Studio. После этого можно перейти к работе с элементами формы. Для создания таблицы в приложении Windows Forms необходимо использовать элемент управления DataGridView, который представляет собой гибкий и мощный инструмент для отображения и редактирования табличных данных.

В окне дизайнера формы можно разместить элемент DataGridView на форме и настроить его свойства, такие как ширина и высота, заголовки столбцов и другие. Затем необходимо подключить источник данных к элементу DataGridView, указав соответствующий источник данных, например, DataSet или DataTable. После этого таблица будет отображать данные из указанного источника.

После создания таблицы на Windows Forms можно осуществлять различные операции с данными, такие как добавление, редактирование и удаление строк, сортировка и фильтрация данных, а также перебор данных. Элемент DataGridView предоставляет набор методов и свойств для управления таблицей и работой с данными.

Важно отметить, что для работы с таблицей на Windows Forms необходимо иметь знания основ программирования на языке C# и понимание принципов работы с элементами управления Windows Forms. Однако, благодаря гибкости и обширным возможностям элемента DataGridView, создание и управление таблицами на Windows Forms становится относительно простой и удобной задачей.

Содержание

  1. Основы создания таблицы на Windows Forms
  2. Установка и настройка среды разработки для Windows Forms
  3. Создание таблицы с помощью компонентов Windows Forms
  4. Настройка внешнего вида таблицы и работы с данными

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

После добавления таблицы на форму можно приступить к настройке ее внешнего вида и свойств. Например, можно определить количество столбцов и строк в таблице, задать заголовки столбцов, установить ширину столбцов и т.д. Эти настройки можно выполнить как в режиме дизайна формы, так и в программном коде.

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

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

Создание таблицы на Windows Forms — это процесс, который требует некоторых знаний и навыков. Однако, благодаря элементу управления DataGridView и гибким возможностям Windows Forms, создание и использование таблицы становится достаточно простой задачей.

Пример таблицы на Windows Forms

Имя Возраст Город
Алексей 25 Москва
Екатерина 30 Санкт-Петербург
Иван 35 Казань

В приведенном примере показана простая таблица с заголовком и тремя строками. Такую таблицу можно создать на Windows Forms с помощью элемента управления DataGridView в несколько простых шагов.

Установка и настройка среды разработки для Windows Forms

Для создания и разработки Windows Forms приложений необходимо установить и настроить среду разработки, специально предназначенную для данной цели.

Одним из популярных инструментов для разработки Windows Forms является интегрированная среда разработки Visual Studio, которая предоставляет широкие возможности для создания и настройки графических интерфейсов.

Для установки Visual Studio следует выполнить следующие шаги:

  1. Зайдите на официальный сайт Microsoft (https://www.visualstudio.com/) и скачайте установочный файл Visual Studio.
  2. Запустите установку и следуйте инструкциям мастера установки.
  3. Выберите необходимые компоненты и настройки для установки Windows Forms.
  4. Дождитесь завершения установки и запустите Visual Studio.

После установки Visual Studio необходимо настроить среду разработки для работы с Windows Forms. Для этого выполните следующие действия:

  1. Откройте Visual Studio и выберите «Создать новый проект» из главного меню.
  2. В окне «Создание проекта» выберите «Windows Forms приложение» и задайте имя проекта.
  3. Нажмите кнопку «Создать» и дождитесь, пока Visual Studio создаст структуру проекта.
  4. После создания проекта откроется дизайнер Windows Forms, где можно начать разработку интерфейса.

Теперь среда разработки настроена для работы с Windows Forms, и вы можете начать создание графических интерфейсов для ваших приложений.

Создание таблицы с помощью компонентов Windows Forms

Для создания таблицы в Windows Forms используется компонент DataGridView. Этот компонент позволяет отображать данные в виде таблицы и управлять ими.

Для начала работы с DataGridView необходимо добавить его на форму. Для этого можно воспользоваться инструментом рисования в дизайнере формы или создать и настроить DataGridView в коде. После добавления на форму компонент DataGridView можно настроить с помощью его свойств и методов.

Чтобы заполнить таблицу данными, необходимо указать источник данных. Для этого можно использовать различные объекты данных, например, массивы, списки или объекты, полученные из базы данных. После указания источника данных, можно указать, какие столбцы и строки будут отображаться в таблице.

Каждый столбец таблицы представляет собой объект DataGridViewColumn. При создании столбцов можно указать различные свойства, такие как заголовок столбца, его ширина, тип данных и др. С помощью методов DataGridView можно добавить столбцы в таблицу и указать их порядок отображения.

Заполнение таблицы данными производится с помощью свойства DataSource объекта DataGridView. Данные могут быть представлены различными объектами, такими как DataTable, DataSet, массивы и др. После указания источника данных, таблица отразит данные и будет готова к отображению пользователю.

Создание таблицы с помощью компонентов Windows Forms — это простой и удобный способ организации отображения данных. Используя компонент DataGridView, можно быстро и эффективно отображать и управлять таблицами в своих приложениях.

Компонент Описание
DataGridView Компонент для отображения таблицы данных
DataGridViewColumn Объект, представляющий столбец таблицы
DataSource Свойство, которое указывает источник данных таблицы

Настройка внешнего вида таблицы и работы с данными

При создании таблицы на Windows Forms можно настроить ее внешний вид и работу с данными для удобства пользователя. Ниже приведены некоторые полезные способы этого:

  • Изменение размеров столбцов и строк: таблицы можно настраивать таким образом, чтобы она отображала данные в наиболее удобном формате. Для этого можно использовать методы, такие как ColumnWidth и RowHeight, чтобы задать ширину столбцов и высоту строк.
  • Добавление заголовков: для более наглядного отображения данных в таблице можно добавить заголовки для каждого столбца. Для этого можно использовать свойство ColumnHeader.
  • Оформление ячеек: стандартно ячейки таблицы имеют простой текстовый вид. Однако можно задать различные стили для ячеек, такие как шрифт, цвет фона, границы и другие параметры. Воспользуйтесь методом CellStyle, чтобы настроить внешний вид ячеек.
  • Сортировка данных: если в таблице представлены данные, которые можно упорядочить, можно включить функцию сортировки. Для этого можно использовать метод Sort, чтобы отсортировать данные по выбранному столбцу.
  • Фильтрация данных: в таблице можно настроить фильтр, чтобы отобрать только нужные данные. Для этого можно использовать методы, такие как Filter или Search.

Настройка внешнего вида таблицы и работы с данными на Windows Forms позволяет создать удобный и интуитивно понятный интерфейс для пользователя. Используя перечисленные выше способы, можно настроить таблицу наиболее эффективно в соответствии с требованиями приложения.

  • Windows git could not read from remote repository git
  • Windows future experience pack что это
  • Windows forms c visual studio 2017
  • Windows forms панель элементов пустая
  • Windows forms c open file