System windows forms datagridviewrow

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

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

В нашей программе мы предусмотрим и реализуем следующие возможности:

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

Вот так будет выглядеть наше приложение:

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

Мы также поддержим контекстное меню для элемента DataGridView, которое будет содержать два пункта меню — «Удалить выбранную книгу» и «Редактировать выбранную книгу». При нажатии на пункт меню «Удалить выбранную книгу» запись с данными о книге будет удаляться из таблицы, а также из списка книг в памяти приложения.

При нажатии на второй пункт меню «Редактировать выбранную книгу» будет отображаться отдельная форма с редактированием данных о книге:

 

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

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

Итак, давайте приступим к созданию проекта в среде разработки Microsoft Visual Studio для нашего приложения.

Создание нового проекта в среде Microsoft Visual Studio

Откройте среду разработки Microsoft Visual Studio и создайте новый проект с типом Приложение Windows Forms (.NET Framework), как показано ниже:

В качестве имени нового проекта задайте DataGridViewSample и выберите местоположение, куда будут сохранены файлы нового проекта (здесь я обычно оставляю все настройки по умолчанию и рекомендую сделать то же самое, просто запомните каталог, указанный в поле «Расположение», чтобы затем открывать его в Проводнике).

Переименование главной формы приложения

После создания проекта будет создана главная форма по умолчанию с именем Form1 и соответствующий ей класс Form1.cs.

Выберем в окне «Обозреватель решений» эту форму и в окне «Свойства» изменим название класса для формы на FrmDataGridViewSampleMain.cs.

В диалоговом окне, запрашивающем подтверждение переименования класса формы и связанных с ней файлов, соглашаемся.

В итоге должно получиться следующее — в окне «Обозреватель решений» форма и зависящие от неё файлы будут переименованы:

А так должно выглядеть окно «Свойства»:

Настройка главной формы приложения и её элементов

Далее нам нужно изменить размеры и свойства главной формы и расположить на ней все нужные нам элементы управления.

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

  • FormBorderStyle — FixedSingle
  • Text — [Allineed.Ru] Пример работы с элементом DataGridView
  • Size — 1026; 568
  • StartPosition — CenterScreen
  • Name — FrmDataGridViewSampleMain
  • MaximizeBox — False
  • MinimizeBox — False

Теперь расположим на главной форме нужные элементы. Для этого в левой части Microsoft Visual Studio находим «Панель элементов» и последовательно перетаскиваем с неё на нашу главную форму следующие элементы, а также устанавливаем им описанные ниже свойства:

1) Один элемент ContextMenuStrip для контекстного меню, которое будет отображаться на элементе DataGridView

Перетаскиваем на форму элемент ContextMenuStrip и устанавливаем ему следующие свойства:

  • Name — ContextMenuStripForGrid

Далее необходимо выбрать этот элемент ContextMenuStrip в нижней части представления конструктора формы, как показано ниже:

После этого в представлении конструктора формы появится выпадающее меню с подсказкой «Вводить здесь». Необходимо ввести с клавиатуры названия для двух новых пунктов меню:

  • &Удалить выбранную книгу
  • &Редактировать выбранную книгу

В результате будут созданы два соответствующих элемента ToolStripMenuItem для контекстного меню (знак & перед текстом пунктов меню позволит при работе программы использовать комбинацию клавиш Alt+<подчёркнутая_буква> для выбора пункта меню с клавиатуры без использования мыши):

Теперь снова последовательно выбираем каждый из этих элементов и устанавливаем им свойства:

Для пункта меню «&Удалить выбранную книгу»:

  • Name — MenuItemRemoveBook

Для пункта меню «&Редактировать выбранную книгу»:

  • Name — MenuItemEditBook

2) Один элемент DataGridView для списка книг

Перетаскиваем на форму элемент DataGridView и устанавливаем ему следующие свойства:

  • CellBorderStyle — RaisedHorizontal
  • ColumnHeadersDefaultCellStyle — открыть окно «Построитель CellStyle» и установить в нём для свойства Font значение: Microsoft Sans Serif; 8,25pt; style=Bold
  • RowsDefaultCellStyle — открыть окно «Построитель CellStyle» и установить в нём для свойства BackColor значение PapayaWhip, а для свойства ForeColor — значение SaddleBrown
  • Location — 12; 41
  • Size — 587; 388
  • ColumnHeadersHeightSizeMode — AutoSize
  • ContextMenuStrip — ContextMenuStripForGrid
  • Name — DataGridViewBooks

3) Один элемент TextBox для текстового представления списка книг в памяти программы

Перетаскиваем на форму элемент TextBox и устанавливаем ему следующие свойства:

  • ScrollBars — Vertical
  • Location — 605; 12
  • Size — 391; 417
  • Multiline — True
  • ReadOnly — True
  • Name — TextBoxBooks

4) Один элемент Label с текстом «Поиск:»

Перетаскиваем на форму элемент Label и устанавливаем ему следующие свойства:

  • Text — Поиск:
  • Location — 12; 15
  • Size — 42; 13
  • Name — LabelSearch

5) Один элемент TextBox для быстрого поиска книги или автора и фильтрации данных в элементе DataGridView

Перетаскиваем на форму элемент TextBox и устанавливаем ему следующие свойства:

  • Text — <оставить поле пустым>
  • Location — 53; 12
  • Size — 546; 20
  • Name — TextBoxSearch

6) Один элемент GroupBox для группировки элементов в нижней части формы

Перетаскиваем на форму элемент GroupBox и устанавливаем ему следующие свойства:

  • Text — Добавить новую книгу в коллекцию:
  • Location — 12; 435
  • Size — 984; 59
  • Name — GroupBoxAddNewBook

Теперь внутрь этого элемента GroupBox перетаскиваем дополнительные элементы и устанавливаем им свойства:

6.1) один элемент Label для названия книги

  • Text — Название:
  • Location — 16; 25
  • Size — 60; 13
  • Name — LabelTitle

6.2) один элемент TextBox для ввода названия книги

  • Text — <оставить поле пустым>
  • Location — 82; 22
  • Size — 294; 20
  • Name — TextBoxTitle

6.3) один элемент Label для автора книги

  • Text — Автор:
  • Location — 393; 25
  • Size — 40; 13
  • Name — LabelAuthor

6.4) один элемент TextBox для ввода автора книги

  • Text — <оставить поле пустым>
  • Location — 439; 22
  • Size — 175; 20
  • Name — TextBoxAuthor

6.5) один элемент Label для года издания книги

  • Text — Год издания:
  • Location — 630; 25
  • Size — 73; 13
  • Name — LabelDatePublished

6.6) один элемент DateTimePicker для ввода года издания книги

  • Format — Custom
  • Location — 717; 22
  • Size — 66; 20
  • CustomFormat — yyyy
  • Name — DateTimePickerDatePublished

6.7) один элемент Button для добавления книги в таблицу

  • Text — &Добавить книгу
  • Location — 823; 20
  • Size — 147; 23
  • Name — ButtonAddBook

Дизайн для главной формы приложения готов, все необходимые элементы на ней присутствуют.

Добавление новой формы для редактирования книги

Добавьте к проекту новую форму и назовите её FrmEditBook. Для добавления новой формы в окне «Обозреватель решений» кликните на проекте DataGridViewSample правой кнопкой мыши (маркер 1 на рисунке ниже), затем выберите пункт меню «Добавить» (маркер 2 на рисунке ниже), а затем выберите пункт меню «Форма (Windows Forms)…» (маркер 3 на рисунке ниже):

В открывшемся диалоговом окне вместо имени класса по умолчанию Form1.cs введите имя нового класса для формы FrmEditBook.cs и нажмите кнопку «Добавить».

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

  • FormBorderStyle — FixedSingle
  • Text — Редактировать книгу
  • Size — 548; 342
  • StartPosition — CenterScreen
  • Name — FrmEditBook
  • MaximizeBox — False
  • MinimizeBox — False 

Далее расположите на форме следующие элементы управления и задайте им соответствующие свойства:

1) Один элемент Label (для текстового поля с названием книги):

  • Text — Название книги:
  • Location — 23; 20
  • Size — 92; 13
  • Name — LabelTitle

2) Один элемент TextBox (для отображения редактируемого названия книги):

  • Text — <оставить поле пустым>
  • Location — 26; 36
  • Size — 476; 20
  • Name — TextBoxTitle

3) Один элемент Label (для текстового поля с автором книги):

  • Text — Автор книги:
  • Location — 23; 81
  • Size — 72; 13
  • Name — LabelAuthor

4) Один элемент TextBox (для отображения редактируемого автора книги):

  • Text — <оставить поле пустым>
  • Location — 26; 97
  • Size — 476; 20
  • Name — TextBoxAuthor

5) Один элемент Label (для поля с выбором года издания книги):

  • Text — Год издания:
  • Location — 23; 144
  • Size — 73; 13
  • Name — LabelDatePublished

6) Один элемент DateTimePicker (поле с выбором года издания книги):

  • Format — Custom
  • Location — 26; 160
  • Size — 89; 20
  • CustomFormat — yyyy
  • Name — DateTimePickerDatePublished

7) Один элемент Button (кнопка «OK»):

  • Text — &OK
  • Location — 346; 236
  • Size — 75; 23
  • DialogResult — OK
  • Name — ButtonOK

8) Один элемент Button (кнопка «Отмена»):

  • Text — &Отмена
  • Location — 427; 236
  • Size — 75; 23
  • DialogResult — Cancel
  • Name — ButtonCancel

Теперь все основные элементы расположены на нашей второй форме «Редактировать книгу». Для завершения дизайна формы нам осталось выставить ещё два дополнительных свойства на форме.

Выберите форму в представлении конструктора и установите свойства из категории «Прочее»:

  • AcceptButton — ButtonOK
  • CancelButton — ButtonCancel

Должно было получиться следующее:

Теперь дизайн второй формы полностью готов. Нажмите комбинацию Ctrl+Shift+S, чтобы сохранить все изменения в проекте.

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

Создаём класс Book для хранения данных о книге

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

Для добавления нового класса в окне «Обозреватель решений» кликните на проекте DataGridViewSample правой кнопкой мыши (маркер 1 на рисунке ниже), затем выберите пункт меню «Добавить» (маркер 2 на рисунке ниже), а затем выберите пункт меню «Класс…» (маркер 3 на рисунке ниже):

В открывшемся диалоговом окне вместо Class1.cs введите имя нового класса: Book.cs и нажмите кнопку «Добавить». В результате будет открыт редактор кода со сгенерированным начальным кодом класса Book. Всё содержимое нужно будет заменить представленным ниже кодом.

Ниже полный код класса Book, который имеет свойства для хранения названия книги (Title), автора книги (Author), а также даты публикации книги (DatePublished). Мы также отдельно будем возвращать год публикации книги (YearPublished), без возможности его редактирования:

using System;

namespace DataGridViewSample {
    public class Book {
        public string Title { get; set; }
        public string Author { get; set; }
        public DateTime DatePublished { get; set; }

        public string YearPublished { get { return DatePublished.ToString("yyyy"); } }

        public Book(string title, string author, DateTime datePublished) {
            Title = title;
            Author = author;
            DatePublished = datePublished;
        }

        public override string ToString() {
            return "\tBook@" + GetHashCode() + "{\r\n" +
                "\t\tTitle: " + Title + "\r\n" +
                "\t\tAuthor: " + Author + "\r\n" +
                "\t\tDatePublished: " + DatePublished + "\r\n" +
                "\t\tYearPublished: " + YearPublished + "\r\n" +
                "\t}";
        }
    }
}

Вставьте весь представленный выше код в редактор и сохраните изменения, нажав Ctrl+S.

Привязка полей формы FrmEditBook к источнику данных

Теперь, когда класс книги Book у нас готов, мы привяжем текстовые поля формы редактирования книги (FrmEditBook) и её элемент DateTimePicker к источнику данных, которым будет являться экземпляр книги.

Чтобы сделать это, выделите в представлении конструктора формы первое текстовое поле TextBoxTitle и в окне «Свойства» для него найдите категорию «Данные», а под ним свойство DataBindings:

 

Раскройте напротив свойства Text выпадающий список и в открывшемся окне раскройте узел «Другие источники данных» и вложенный в него «Источники данных проекта». Вы увидите созданный ранее класс Book и его поля, как показано ниже на рисунке. Выберите поле Title для его привязки к свойству Text для текстового поля:

В результате вы должны увидеть следующее — напротив свойства Text появился индикатор привязки к источнику данных — bookBindingSource — Title:

Также обратите внимание на нижнюю часть под формой в представлении конструктора — можно увидеть добавленный к форме источник данных с именем bookBindingSource:

Проделайте аналогичную привязку к полям класса Book для остальных элементов формы:

Для элемента TextBoxAuthor необходимо выбрать привязку данных для свойства Text к полю Author в классе Book. Но в этот раз нужно уже выбирать поле из созданного источника bookBindingSource, поскольку теперь он есть на форме:

 

Для элемента DateTimePickerDatePublished необходимо выбрать привязку данных для свойства Value к полю DatePublished в классе Book:

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

Программируем главную форму приложения (FrmDataGridViewSampleMain)

Добавление полей формы

В начало класса формы мы добавим список книг с именем books, а также флаг cancelContextMenu, который будет отвечать за то, чтобы не показывать контекстное меню для элемента DataGridView при определённых условиях (какие именно это условия мы узнаем чуть позже):

using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;

namespace DataGridViewSample {
    public partial class FrmDataGridViewSampleMain : Form {
        /// <summary>
        /// список книг
        /// </summary>
        private List<Book> books = new List<Book>();

        /// <summary>
        /// флаг отмены отображения контекстного меню для элемента DataGridView
        /// </summary>
        private bool cancelContextMenu = false;

        // ... остальной код формы
    }
}

Вставьте код для этих двух полей в начало класса формы FrmDataGridViewSampleMain, как показано в листинге и сохраните изменения, нажав Ctrl+S.

Инициализация списка книг тестовыми данными

Далее нам нужно инициализировать некоторую тестовые данные с книгами, добавив их в список books. Эти данные будут затем загружаться в элемент DataGridView сразу при запуске приложения. Добавим в класс формы новый метод InitTestBooksData(), который будет инициализировать список книг и добавлять туда некоторые известные произведения классиков литературы с их авторами и годами публикации книг. Для даты публикации книги в нашем приложении будет важен только год издания, поэтому число и месяц публикации произведения мы будем принимать везде по умолчанию за 1 января того самого года, в котором была издана книга:

        private void InitTestBooksData() {
            books.Add(new Book("Война и мир", "Лев Николаевич Толстой", DateTime.Parse("1867-01-01")));
            books.Add(new Book("Анна Каренина", "Лев Николаевич Толстой", DateTime.Parse("1877-01-01")));
            books.Add(new Book("После бала", "Лев Николаевич Толстой", DateTime.Parse("1911-01-01")));
            books.Add(new Book("Юность", "Лев Николаевич Толстой", DateTime.Parse("1857-01-01")));
            books.Add(new Book("Кавказский пленник", "Лев Николаевич Толстой", DateTime.Parse("1872-01-01")));
            books.Add(new Book("Преступление и наказание", "Фёдор Михайлович Достоевский", DateTime.Parse("1866-01-01")));
            books.Add(new Book("Евгений Онегин", "Александр Сергеевич Пушкин", DateTime.Parse("1833-01-01")));
            books.Add(new Book("Капитанская дочка", "Александр Сергеевич Пушкин", DateTime.Parse("1836-01-01")));
            books.Add(new Book("Руслан и Людмила", "Александр Сергеевич Пушкин", DateTime.Parse("1820-01-01")));
            books.Add(new Book("Метель", "Александр Сергеевич Пушкин", DateTime.Parse("1831-01-01")));
            books.Add(new Book("Пиковая дама", "Александр Сергеевич Пушкин", DateTime.Parse("1834-01-01")));
            books.Add(new Book("Мать", "Максим Горький", DateTime.Parse("1906-01-01")));
            books.Add(new Book("Мёртвые души", "Николай Васильевич Гоголь", DateTime.Parse("1842-01-01")));
            books.Add(new Book("Шинель", "Николай Васильевич Гоголь", DateTime.Parse("1842-01-01")));
            books.Add(new Book("Тарас Бульба", "Николай Васильевич Гоголь", DateTime.Parse("1835-01-01")));
            books.Add(new Book("Нос", "Николай Васильевич Гоголь", DateTime.Parse("1836-01-01")));
            books.Add(new Book("Вечера на хуторе близ Диканьки", "Николай Васильевич Гоголь", DateTime.Parse("1830-01-01")));
            books.Add(new Book("Ночь перед рождеством", "Николай Васильевич Гоголь", DateTime.Parse("1832-01-01")));
            books.Add(new Book("Вий", "Николай Васильевич Гоголь", DateTime.Parse("1835-01-01")));
            books.Add(new Book("Повесть о капитане Копейкине", "Николай Васильевич Гоголь", DateTime.Parse("1842-01-01")));
            books.Add(new Book("Заколдованное место", "Николай Васильевич Гоголь", DateTime.Parse("1832-01-01")));
            books.Add(new Book("Портрет", "Николай Васильевич Гоголь", DateTime.Parse("1835-01-01")));
            books.Add(new Book("Тихий Дон", "Михаил Александрович Шолохов", DateTime.Parse("1928-01-01")));
        }
Метод для фильтрации списка книг

Теперь создадим метод GetFilteredBooks(). Он будет возвращать отфильтрованный список книг, который мы будем формировать из нашего исходного списка books, в зависимости от содержимого текстового поля с фильтром TextBoxSearch. Как только мы будем что-то вводить в поле-фильтр TextBoxSearch, то этот введённый текст будет приводиться к нижнему регистру, и мы будем просматривать все книги из списка books, пытаясь найти среди их названий, авторов и годов публикации введённый текст в поле-фильтре. Если текст будет найден, то книга будет добавлена в результирующий список result, в противном же случае она будет проигнорирована, что в дальнейшем придаст элементу DataGridView эффект динамической фильтрации при каждом вводе текста в поисковый фильтр. Код этого метода представлен ниже, добавим его в класс формы:

        private List<Book> GetFilteredBooks() {
            List<Book> result = new List<Book>();
                       
            string searchString = TextBoxSearch.Text;

            if (searchString.Length == 0) {
                return books;
            }

            searchString = searchString.ToLower();

            foreach (Book book in books) {                
                if ((book.Title.Length > 0 && book.Title.ToLower().Contains(searchString)) || 
                    (book.Author.Length > 0 && book.Author.ToLower().Contains(searchString)) ||
                    (book.YearPublished.Length > 0 && book.YearPublished.Contains(searchString))) {
                    result.Add(book);
                }
            }
            return result;
        }
Метод для обновления содержимого элемента DataGridView

Далее мы добавим в код формы метод RefreshDataGridView(), который будет обновлять данные в элементе DataGridView главной формы. В качестве источника данных (свойство DataSource элемента DataGridView) мы будем устанавливать результат вызова метода GetFilteredBooks(). При обновлении элемента DataGridView мы также установим названия его столбцов и их ширину. Ниже код этого метода:

        private void RefreshDataGridView() {
            DataGridViewBooks.DataSource = null;
            DataGridViewBooks.DataSource = GetFilteredBooks();

            DataGridViewBooks.Columns["Title"].HeaderText = "Название";
            DataGridViewBooks.Columns["Title"].Width = 200;

            DataGridViewBooks.Columns["Author"].HeaderText = "Автор";
            DataGridViewBooks.Columns["Author"].Width = 200;

            DataGridViewBooks.Columns["DatePublished"].HeaderText = "Дата издания";
            DataGridViewBooks.Columns["DatePublished"].Width = 200;
            DataGridViewBooks.Columns["DatePublished"].Visible = false;

            DataGridViewBooks.Columns["YearPublished"].HeaderText = "Год публикации";
            DataGridViewBooks.Columns["YearPublished"].Width = 126;
        }
Метод для отображения внутреннего содержимого списка книг

Теперь нам будет нужен отдельный метод для обновления текстового поля TextBoxBooks, которое используется для отображения внутреннего содержимого основного списка books. Назовём новый метод UpdateBooksListDetails() и добавим к коду главной формы:

        private void UpdateBooksListDetails() {
            StringBuilder sb = new StringBuilder();
            sb.Append("Books: [\r\n");
            foreach (Book b in books) {
                sb.Append(b.ToString());
                sb.Append("\r\n");
            }            
            sb.Append("]");

            TextBoxBooks.Text = sb.ToString();
        }

Как видим, он просто пробегает циклом foreach по списку книг и добавляет текстовое представление очередной книги к строковому буферу (переменная sb). В конце метода содержимое строкового буфера sb мы записываем в свойство Text текстового поля TextBoxBooks

Метод для обновления всех данных (список книг в элементе DataGridView и внутреннее содержимое списка книг)

Создадим ещё один небольшой метод RefreshGridAndBookDetails(), который будет вызывать два уже ранее добавленных метода. Этот метод будет сразу обновлять и сам элемент DataGridView, и текстовое поле с содержимым списка books:

        private void RefreshGridAndBookDetails() {
            RefreshDataGridView();
            UpdateBooksListDetails();
        }
Метод для управления доступностью кнопки «Добавить книгу»

Добавим метод UpdateButtonAddBookState(), который будет регулировать доступность кнопки «Добавить книгу» . Кнопка должна быть доступна только тогда, когда оба текстовых поля с названием и автором книги содержат текст:

        private void UpdateButtonAddBookState() {
            ButtonAddBook.Enabled = TextBoxTitle.Text.Length > 0 && TextBoxAuthor.Text.Length > 0;
        }
Пишем логику при загрузке главной формы 

Нам нужно добавить код, который будет выполняться сразу при загрузке формы. Для этого нужно сгенерировать в коде формы обработчик события Load. Это можно сделать перейдя к представлению конструктора формы и дважды кликнув по форме — будет добавлен пустой метод FrmDataGridViewSampleMain_Load. Теперь мы добавим в него следующий код с вызовом трёх методов InitTestBooksData(), RefreshGridAndBookDetails() и UpdateButtonAddBookState():

        private void FrmDataGridViewSampleMain_Load(object sender, EventArgs e) {
            InitTestBooksData();
            RefreshGridAndBookDetails();
            UpdateButtonAddBookState();
        }

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

  1. список с книгами books будет наполнен тестовыми данными — это достигается вызовом метода InitTestBooksData()
  2. будет обновлено содержимое элемента DataGridView и текстового поля TextBoxBooks — это достигается вызовом метода RefreshGridAndBookDetails()
  3. будет установлена доступность кнопки «Добавить книгу» — это достигается вызовом метода UpdateButtonAddBookState()

Теперь вернёмся в представление конструктора формы и дважды кликнем по кнопке «Добавить книгу», чтобы сгенерировался метод-обработчик для события Click (т.е. события клика по кнопке). Добавим в него следующий код:

        private void ButtonAddBook_Click(object sender, EventArgs e) {
            DateTime selectedDate = DateTimePickerDatePublished.Value;
            DateTime truncatedDate = DateTime.Parse(selectedDate.ToString("dd.MM.yyyy"));

            Book newBook = new Book(TextBoxTitle.Text, TextBoxAuthor.Text, truncatedDate);
            books.Add(newBook);
            RefreshGridAndBookDetails();

            TextBoxTitle.Text = "";
            TextBoxAuthor.Text = "";
            DateTimePickerDatePublished.Value = DateTime.Now;

            TextBoxTitle.Focus();
        }

В переменную selectedDate мы получаем значение даты и времени, выбранное в элементе DateTimePickerDatePublished. Это значение содержит выбранную дату вместе с текущим временем. Время нам не нужно, поэтому мы записываем в переменную truncatedDate значение, которое содержит только дату. Далее остаётся только создать новый экземпляр книги newBook со значениями названия, автора и даты публикации и добавить его в основной список books, после чего обновить данные в элементе DataGridView и текстовом поле с содержимым всего списка книг. Напоследок мы также очищаем все поля в нижней части формы и устанавливаем дату в текущую, а также явно устанавливаем фокус на текстовое поле с названием книги — это необходимо для удобства последовательного ввода нескольких книг.

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

  • CellEndEdit — это событие возникает при завершении редактирования содержимого ячейки
  • DataError — это событие возникает при появлении ошибки при редактировании ячейки. В нашем случае оно будет вызываться при попытке установить некорректное значение года публикации книги (к примеру, если попытаемся ввести некорректную дату)
  • MouseDown — событие возникает при клике мышью на элементе DataGridView. Его мы будем обрабатывать в случае нажатия правкой кнопки мыши в целях полного выделения строки, над которой произошёл клик, а также установки специального флага скрытия контекстного меню

Для этого выбираем на форме элемент DataGridView, а затем в окне «Свойства» кликаем на иконку «молнии». В списке событий находим сначала CellEndEdit и дважды кликаем напротив имени этого события, в результате чего в коде формы будет сгенерирован пустой метод-обработчик DataGridViewBooks_CellEndEdit. Аналогичное действие проделываем, дважды кликая напротив событий DataError и MouseDown.

Теперь пора написать код для этих сгенерированных методов-обработчиков.

Начнём с первого — DataGridViewBooks_CellEndEdit. Внутри него мы напишем код, который из входного параметра e с типом DataGridViewCellEventArgs получит индексы строки и столбца в переменные row и col, соответственно. После этого в переменную cell мы получим ссылку на ячейку элемента DataGridView, которая и была отредактирована. Далее нам нужно получить содержимое ячейки с помощью свойства Value — его мы устанавливаем в переменную cellValue с типом object (на этом этапе мы не знаем информацию о точном типе данных для значения отредактированной ячейки). Теперь мы можем получить ссылку на редактируемую книгу в переменную book — индекс отредактированной книги в списке books совпадает с индексом строки в элементе DataGridView. А чтобы обновить конкретное свойство экземпляра книги мы смотрим на индекс столбца col и приводим cellValue уже к конкретному типу данных и устанавливаем в конкретное свойство для экземпляра книги. После этого мы можем вызывать метод UpdateBooksListDetails() для обновления содержимого текстового поля TextBoxBooks:

        private void DataGridViewBooks_CellEndEdit(object sender, DataGridViewCellEventArgs e) {
            int row = e.RowIndex;
            int col = e.ColumnIndex;

            DataGridViewCell cell = DataGridViewBooks[col, row];

            object cellValue = cell.Value;

            Book book = books[row];
            switch (col) {
                case 0:
                    book.Title = (string)cellValue;
                    break;
                case 1:
                    book.Author = (string)cellValue;
                    break;
                case 2:                    
                    book.DatePublished = (DateTime)cellValue;                    
                    break;
            }

            UpdateBooksListDetails();
        }

Теперь перейдем к методу-обработчику DataGridViewBooks_DataError и напишем код для него.

Аналогичным образом из параметра e можно извлечь индексы столбца и строки в переменные col и row. Далее нас будет интересовать свойство EditedFormattedValue для ячейки по этим индексам — его мы получим в переменную editedValue. В конце метода мы проверим, что если тип исключения — это FormatException и при этом индекс столбца равен 2 (т.е. мы редактируем какую-то ячейку в столбце «Год публикации»), то мы выводим сообщение о необходимости ввода корректной даты, а также отменяем событие, устанавливая свойство Cancel в true. Ниже код этого метода:

        private void DataGridViewBooks_DataError(object sender, DataGridViewDataErrorEventArgs e) {
            int col = e.ColumnIndex;
            int row = e.RowIndex;
            
            object editedValue = DataGridViewBooks[col, row].EditedFormattedValue;

            if (e.Exception is FormatException fe && col == 2) {
                MessageBox.Show("Введите корректную дату, т.к. значение '" + editedValue.ToString() + "' не является датой", "Ошибка", MessageBoxButtons.OK, MessageBoxIcon.Error);
                e.Cancel = true;
            }
        }

Перейдем к последнему методу-обработчику для элемента DataGridView — DataGridViewBooks_MouseDown и напишем код для него. Прежде всего мы должны проверить, что клик по таблице с книгами произведён именно правой кнопкой мыши (MouseButtons.Right). Далее мы используем специальный метод HitTest, доступный для элемента DataGridView — он поможет вернуть специальную информацию о координатах клика в переменную hitTestInfo, в частности, мы сможем получить доступ к индексу строки и столбца, по которым произошёл клик мышью. Мы проверим, что если эти индексы — неотрицательные, то это значит, что текущее выделение для элемента DataGridView необходимо очистить и выделить только ту строку, над которой находился курсор мыши в момент клика. В этом случае мы также сбросим флаг cancelContextMenu в false — это означает, что контекстное меню показать надо. В противном же случае — если мы кликнули где-то по заголовкам или служебным областям элемента DataGridView — индексы будут отрицательными и в развилке else мы выставим флаг cancelContextMenu в true:

        private void DataGridViewBooks_MouseDown(object sender, MouseEventArgs e) {
            if (e.Button == MouseButtons.Right) {
                var hitTestInfo = DataGridViewBooks.HitTest(e.X, e.Y);
                if (hitTestInfo.RowIndex >= 0 && hitTestInfo.ColumnIndex >= 0) {
                    DataGridViewBooks.ClearSelection();
                    DataGridViewBooks.Rows[hitTestInfo.RowIndex].Selected = true;
                    cancelContextMenu = false;
                } else {                    
                    cancelContextMenu = true;
                }
            }
        }

Раз уж мы заговорили про специальный флаг cancelContextMenu — пора им воспользоваться и написать логику, которая будет отменять показ контекстного меню. Для этого нужно вернуться на главную форму в представление конструктора, выбрать контекстное меню ContextMenuStripForGrid и сгенерировать для него обработчик события Opening. Это событие возникает в момент открытия контекстного меню, при этом его можно отменить, тогда контекстное меню не будет отображено. В коде мы как раз проверим наш специальный флаг необходимости отмены показа контекстного меню и отменим само событие, если флаг установлен:

        private void ContextMenuStripForGrid_Opening(object sender, System.ComponentModel.CancelEventArgs e) {
            if (cancelContextMenu) {
                e.Cancel = true;
            }
        }
Обработка событий контекстного меню

Теперь мы напишем код, который будет обрабатывать события клика на элементах контекстного меню ContextMenuStripForGrid. Для этого нужно перейти к представлению конструктора формы, выбрать в нижней части элемент ContextMenuStripForGrid и дважды кликнуть по пункту меню «&Удалить выбранную книгу». В результате будет сгенерирован обработчик клика на этом пункте меню с названием MenuItemRemoveBook_Click. Затем нужно повторить то же самое для пункта меню «&Редактировать выбранную книгу» и сгенерировать обработчик MenuItemEditBook_Click.

Теперь напишем для них код:

        private void MenuItemRemoveBook_Click(object sender, EventArgs e) {
            DataGridViewSelectedRowCollection selectedRows = DataGridViewBooks.SelectedRows;
            foreach (DataGridViewRow selectedRow in selectedRows) {
                int rowIndex = selectedRow.Index;

                if (rowIndex < 0) {
                    continue;
                }
                
                Book book = books[rowIndex];
                
                DialogResult dlgConfirm = MessageBox.Show("Удалить эту книгу?\r\n\r\nАвтор: " + book.Author + "\r\nНазвание: " + book.Title + "\r\nГод публикации: " + book.YearPublished, "Подтвердите", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question);
                if (dlgConfirm == DialogResult.Yes) {
                    books.RemoveAt(rowIndex);
                }
            }

            RefreshGridAndBookDetails();
        }

        private void MenuItemEditBook_Click(object sender, EventArgs e) {
            DataGridViewSelectedRowCollection selectedRows = DataGridViewBooks.SelectedRows;

            foreach (DataGridViewRow selectedRow in selectedRows) {
                int rowIndex = selectedRow.Index;

                if (rowIndex < 0) {
                    continue;
                }

                Book book = books[rowIndex];

                FrmEditBook frmEdit = new FrmEditBook();
                frmEdit.EditedBook = book;
                frmEdit.BookUpdatedEvent += FrmEdit_BookUpdatedEvent;
                frmEdit.Show();
            }
        }

Как видим, в обработчике MenuItemRemoveBook_Click происходит получение выбранных строк таблицы в коллекцию selectedRows, а затем цикл по этой коллекции. На самом деле выбранная строка всегда будет одна, но для надёжности мы делаем цикл и в цикле проверяем, что индекс выбранной строки неотрицательный. В этом случае мы получаем выбранную книгу из списка books (её индекс в списке равен индексу выбранной строки таблицы) и выдаём диалоговое окно с подтверждением необходимости удаления книги. Если в окне диалога удаление подтверждено, то книга удаляется из списка.

Во втором обработчике MenuItemEditBook_Click у нас немного другая задача. Мы должны отобразить вторую форму для редактирования выбранной в таблице записи. Легко заметить, что логика с получением выбранных строк таблицы и проверки в цикле индекса аналогична первому обработчику, только в этот раз мы вместо удаления книги создаём экземпляр формы FrmEditBook, устанавливаем её свойство EditedBook текущей выбранной книге, а также подписываемся на событие BookUpdatedEvent, после чего отображаем форму.

Ниже код нового метода FrmEdit_BookUpdatedEvent, который надо добавить в код главной формы. Всё, что он делает, — это вызывает метод обновления данных на форме:

        private void FrmEdit_BookUpdatedEvent(Book updatedBook) {
            RefreshGridAndBookDetails();
        }

Последнее, что нам осталось добавить в код главной формы — это реакция на изменения текстовых полей. У нас их на форме три:

  • TextBoxTitle — для ввода названия книги (при добавлении новой)
  • TextBoxAuthor — для ввода автора книги (при добавлении новой)
  • TextBoxSearch — поисковое поле-фильтр для быстрого поиска по списку книг

Кликните дважды по каждому из них из представления конструктора формы — должны сгенерироваться пустые методы-обработчики для события TextChanged, которое возникает при изменении текста в текстовом поле.

Наполним эти пустые методы следующим образом:

        private void TextBoxTitle_TextChanged(object sender, EventArgs e) {
            UpdateButtonAddBookState();
        }

        private void TextBoxAuthor_TextChanged(object sender, EventArgs e) {
            UpdateButtonAddBookState();
        }

        private void TextBoxSearch_TextChanged(object sender, EventArgs e) {
            RefreshDataGridView();
        }

При изменении названия или автора книги будет вызываться UpdateButtonAddBookState() — это необходимо, чтобы делать кнопку «Добавить книгу» доступной при наличии всех данных по книге и наоборот — делать её недоступной, если хотя бы одно из полей не заполнено. А вот при изменении поля-фильтра мы будем вызывать RefreshDataGridView(), который «перерисует» элемент DataGridView — в зависимости от текста в поле-фильтре.

На этом код главной формы полностью готов.

Программируем форму редактирования книги (FrmEditBook)

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

Сначала дважды кликнем по форме из представления конструктора — это сгенерирует пустой метод-обработчик FrmEditBook_Load для события Load формы.

Затем возвращаемся снова к конструктору формы и дважды кликаем по кнопке ButtonCancel — в результате будет сгенерирован пустой метод-обработчик ButtonCancel_Click, который будет отвечать за обработку события клика по кнопке «&Отмена».

Аналогичное действие делаем для второй кнопки ButtonOK — из представления конструктора формы дважды кликаем по ней, чтобы сгенерировать пустой метод-обработчик ButtonOK_Click.

Далее необходимо наполнить пустые сгенерированные методы представленным ниже кодом или просто выделить весь фрагмент и заменить им код в редакторе:

using System;
using System.Windows.Forms;

namespace DataGridViewSample {
    public partial class FrmEditBook : Form {
        /// <summary>
        /// делегат, который описывает контракт для события обновления данных для книги
        /// </summary>
        /// <param name="updatedBook">отредактированная книга</param>
        public delegate void DelegateUpdateBook(Book updatedBook);

        /// <summary>
        /// событие обновления данных для книги
        /// </summary>
        public event DelegateUpdateBook BookUpdatedEvent;

        /// <summary>
        /// свойство содержит ссылку на редактируемую книгу
        /// </summary>
        public Book EditedBook { get; set; }

        public FrmEditBook() {
            InitializeComponent();
        }

        private void FrmEditBook_Load(object sender, EventArgs e) {
            // Помещаем в источник данных экземпляр для редактируемой книги
            bookBindingSource.Add(EditedBook);
        }

        private void ButtonCancel_Click(object sender, EventArgs e) {
            Close();
        }

        private void ButtonOK_Click(object sender, EventArgs e) {
            // Получаем текущую обновлённую книгу из свойства Current
            // для источника данных bookBindingSource
            Book bookUpdated = (Book)bookBindingSource.Current;

            // Если событие BookUpdatedEvent не равно null, это значит, что
            // на него есть подписчики. Следовательно, вызовем это событие, передавая 
            // в него экземпляр обновлённой книги
            if (BookUpdatedEvent != null) {
                BookUpdatedEvent(bookUpdated);
            }
            Close();
        }
    }
}

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

Наше приложение полностью готово, можем запустить его из среды разработки при помощи клавиши F5 или нажав на кнопку «Пуск».

Заключение

Попробуйте поработать со списком книг — отфильтровать его содержимое, вводя различный текст в поисковое поле-фильтр. Также можно редактировать отдельные записи прямо в таблице — либо при помощи двойного клика по ячейкам, либо нажимая клавишу F2 для входа в режим редактирования ячейки. Обратите внимание, что ячейки таблицы с годом издания книги невозможно отредактировать. Год издания можно поменять только через вторую форму «Редактировать книгу», которая открывается из контекстного меню при клике правой кнопкой мыши по строкам таблицы.

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

Друзья, на этом всё, надеюсь, что урок вам понравился, при наличии вопросов/пожеланий — используйте форму комментариев внизу статьи.

Ссылка на готовый проект из этой статьи:

https://allineed.ru/our-products/download/4-allineed-ru-examples/15-csharp-demo-working-with-datagridview

Удачи и успехов в написании хороших программ!

  1. DataGridView in C#

  2. Add Rows in DataGridView in C#

How to Add a Row in DataGridView Using C#

In this article, we’ll learn about DataGridView in C#. Let’s first take some idea about DataGridView and why we need to store data in the table, i.e., in rows and columns.

Next, we will discuss various ways to add rows to the grid.

In the past, most developers stored their data in files. Whenever they needed it, they had to search through all the files sequentially, which was time-consuming.

The tables were invented to overcome this problem.

In the table, data is stored in rows and columns sequentially in a well-organized manner. Tables provide fast and efficient readability across rows and columns without being time-consuming.

Grid is also the form of the table in the form of cells, i.e., rows and columns.

DataGridView in C#

Visual Studio 2008 has the DataGridView control available in Windows Forms controls. This control has added extensive power to manage data compared to previous versions.

Besides strength, this control provides flexibility to display data in the row-column form.

We can use the DataGridView control to show read-only views for a small amount of data. You can also use it for large data sets to show editable views.

Besides small and large data sets, you can also display master details using this control.

The DataGridView control is available for a variety of different data sources for the view as well as for editing. This control has a simple and intuitive way of binding data to this control.

To bind multiple tables in a data source, set it as a string in the property of DataMember.

The DataGridView control will bind to any class instance that implements the following interfaces:

  1. IList interface also includes one-dimensional arrays.
  2. IListSource interface. The examples are the DataSet classes and DataTable.
  3. IBindingList interface, like BindingList<(Of <(T>)>) class.
  4. IBindingListView interface, like the BindingSource class.

The DataGridView control can bind data to the public attributes of the objects described by the above interfaces. The DataGridView control mainly attaches a BindingSource, whereas the BindingSource is bound to another reference data source or with the business object.

This control also supports data binding to the properties collection returned by an ICustomTypeDescriptor interface.

The DataGridView in C# displays data in a customizable grid, i.e., in tabular form with Windows Form. It is part of the System.Windows.Forms namespace.

The syntax of using a grid is given below.

[System.ComponentModel.ComplexBindingProperties("DataSource", "DataMember")]
[System.Windows.Forms.Docking(System.Windows.Forms.DockingBehavior.Ask)]
public class DataGridView : System.Windows.Forms.Control, System.ComponentModel.ISupportInitialize

You can customize the cells, rows, columns, and borders through the DataGridView class. The DataGridView control displays data with or without a data source.

If you still need to provide a Data source, you can add rows and columns in DataGridView by rows and columns properties. You can also access rows and column collections using DataGridView rows and cols objects.

In this article, our primary focus is adding rows in the data grid view, so let’s find some methods.

Add Rows in DataGridView in C#

We will discuss multiple ways to add rows in DataGridView. We will present coding details with each method.

Manual Addition of Rows

The easiest way to add rows in DataGridView can be done manually using the Rows.Add() method in the data grid view. In the following example, in the MyForm.cs class, the add_Data button function is written, which will display rows.

You can create a form design in WPF FormDesign using a grid and a button that displays the grid.

using System;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace Manual_Addition_of_Rows_Datagrid {
  public partial class MyForm : FormDesign {
    public MyForm() {
      IntializeComponent();
    }
    private void add_Data(object sender, EventArgs e) {
      dataGridView1.ColumnCount = 3;
      dataGridView1.Columns[0].Name = "ID";
      dataGridView1.Columns[1].Name = "Course Name";
      dataGridView1.Columns[2].Name = "Marks";

      string[] row = new string[] { "1", "OOP", "75" };
      dataGridView1.Rows.Add(row);
      row = new string[] { "2", "DSA", "86" };
      dataGridView1.Rows.Add(row);
      row = new string[] { "3", "AOA", "67" };
      dataGridView1.Rows.Add(row);
    }
  }
}

You can also access the DataGridView control’s columns using the Columns collection and the DataGridView control’s rows using the Rows collection.

If DataGridView is not bound to any data table or data set, we can add new rows with the help of the following code.

var index = dataGridView1.Rows.Add();
dataGridView1.Rows[index].Cells["Column1"].Value = "Column1 value";
dataGridView1.Rows[index].Cells["Column2"].Value = 9.5;

Adding a New Row Dynamically

The following example shows how you can dynamically add columns and rows in the grid in the Windows application form Form1. After creating the project, add the dataGridView from the toolbox to your Form1.cs[Design] and click on the dock for the container option from the top right button of the grid.

Now go to the Form1.cs file and do some changes to the Form. First, add the namespaces, as given below.

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

namespace AddingRowsColumnsInGrid {
  public partial class Form1 : Form {
    public Form1() {
      InitializeComponent();
    }
    public void updateGrid() {
      // Update the data grid view here dynamically
      // Add columns
      dataGridView1.ColumnCount = 4;
      dataGridView1.Columns[0].Name = "Bus Id";
      dataGridView1.Columns[1].Name = "Bus Name";
      dataGridView1.Columns[2].Name = "Bus Model";
      dataGridView1.Columns[3].Name = "Bus Color";

      // Now adding rows
      ArrayList arrRow = new ArrayList();
      arrRow.Add("1");
      arrRow.Add("School bus");
      arrRow.Add("2000");
      arrRow.Add("Yellow");
      dataGridView1.Rows.Add(arrRow.ToArray());

      arrRow = new ArrayList();
      arrRow.Add("2");
      arrRow.Add("Speedo bus");
      arrRow.Add("2014");
      arrRow.Add("Red");
      dataGridView1.Rows.Add(arrRow.ToArray());

      arrRow = new ArrayList();
      arrRow.Add("3");
      arrRow.Add("Metro bus");
      arrRow.Add("205");
      arrRow.Add("Orange");
      dataGridView1.Rows.Add(arrRow.ToArray());
    }
    private void Form1_Load_1(object sender, EventArgs e) {
      updateGrid();
    }
  }
}

In the above code, you can see that initialize the form component and then create a Form1_Load_1 function to handle objects and events that occurred on the grid and pass the updateGrid() where to add columns and rows. Rows in the grid have been added to the ArrayList object as it can store objects in the group and can manipulate them.

The output of the above code is given below.

Adding row Dynamically

Adding Rows in Grid Through the Data Table

In the C# WinForm, multiple ways exist to add data to the grid. Simply put, the data table can be defined as an object mainly used in databases.

It is like a database table having rows and columns. If you want to read more about the data table, you can visit the article by Microsoft.

In the below example, you can see that first, we created the data table object and added columns and rows in the grid using the built-in properties of the data table. The data source is also the property of the data table, mainly used to get or set the data for the DataGridView.

When the Add_Row is pressed after filling data in textboxes, the data source will populate the data to the grid.

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

namespace SampleGridData {
  public partial class Form1 : Form {
    public Form1() {
      InitializeComponent();
    }
    DataTable dt = new DataTable();
    private void Form1_Load(object sender, EventArgs e) {
      dt.Columns.Add("Emp Id", typeof(int));
      dt.Columns.Add("Ename", typeof(string));
      dt.Columns.Add("Company", typeof(string));
      dt.Columns.Add("Email", typeof(string));

      dt.Rows.Add(1, "Alexa", "Apple", "alexa123@apple.io");
      dt.Rows.Add(2, "Hugh Jack", "Microsoft", "hugh345@microsoft.com");
      dt.Rows.Add(3, "Jacob", "HP", "jacob678@hp.io");
      dt.Rows.Add(4, "Ariana", "Huawive", "arina86@huaweiv.com");

      dataGridView1.DataSource = dt;
    }
    private void button1_Click(object sender, EventArgs e) {
      dt.Rows.Add(textBox1.Text, textBox2.Text, textBox3.Text, textBox4.Text);
      dataGridView1.DataSource = dt;
    }
  }
}

The output of the above code is:

fullgrid

Adding Rows Through Clone Method

In C#, you can add rows in the grid using the clone method. Clone means copying the data from one DataGridView to another for adding rows and columns in a grid.

Although its primary purpose is to copy the data from one grid to another, you can add rows. For example:

DataGridViewRow myRow = (DataGridViewRow)myGrid.Rows[0].Clone();
myRow.Cells[2].Value = "My first Grid";
myRow.Cells[4].Value = 23.5;
myGrid.Rows.Add(myRow);

The above code represents the one-row value to be added to the grid. However, you can also create a row template, as it provides better arrangements of rows in a cell.

For example:

DataGridViewRow r1 = (DataGridViewRow)myGrid1.RowTemplate.Clone();
r1.CreateCells(myGrid1, "col1", "col2", "col3");
myGrid1.Rows.Add(row);

Although there are different methods to add rows in the data grid view dynamically, here are a few examples:

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

namespace AddingRowsColumnsInGrid {
  public partial class Form1 : Form {
    public Form1() {
      InitializeComponent();
    }
    public void updateGrid() {
      dataGridView1.ColumnCount = 4;
      dataGridView1.Columns[0].Name = "Bus Id";
      dataGridView1.Columns[1].Name = "Bus Name";
      dataGridView1.Columns[2].Name = "Bus Model";
      dataGridView1.Columns[3].Name = "Bus Color";

      dataGridView1.AllowUserToAddRows = true;
      DataGridViewRow row = (DataGridViewRow)dataGridView1.Rows[0].Clone();
      row.Cells[0].Value = "1";
      row.Cells[1].Value = "School bus";
      row.Cells[2].Value = "2000";
      row.Cells[3].Value = "Yellow";
      dataGridView1.Rows.Add(row);

      row = (DataGridViewRow)dataGridView1.Rows[0].Clone();
      row.Cells[0].Value = "4";
      row.Cells[1].Value = "Speedo bus";
      row.Cells[2].Value = "2014";
      row.Cells[3].Value = "Red";
      dataGridView1.Rows.Add(row);

      row = (DataGridViewRow)dataGridView1.Rows[0].Clone();
      row.Cells[0].Value = "3";
      row.Cells[1].Value = "Metro bus";
      row.Cells[2].Value = "2015";
      row.Cells[3].Value = "Orange";
      dataGridView1.Rows.Add(row);

      row = (DataGridViewRow)dataGridView1.Rows[0].Clone();
      row.Cells[0].Value = "4";
      row.Cells[1].Value = "Daewoo bus";
      row.Cells[2].Value = "2021";
      row.Cells[3].Value = "Blue";
      dataGridView1.Rows.Add(row);
    }
    private void Form1_Load_1(object sender, EventArgs e) {
      updateGrid();
    }
  }
}

We have just used the above code for this example as it is easy to understand. In DataGridView, the clone property is used to copy the rows and their properties and populate the row copy with the original one.

In the above code, we have used the clone method to copy the rows. To read more about the clone method, you can visit this page.

The output of the above code is:

clone

You can visit this page to read about adding rows in the data grid view. If you still have ambiguity in adding rows in the grid, you can also read this article.

We have discussed DataGridView in detail. We have discussed multiple ways to bind data to DataGridView.

We hope you have a good idea about the data grid view and its functionalities and that you are comfortable adding rows through different grid methods and setting its property.

Enjoying our tutorials? Subscribe to DelftStack on YouTube to support us in creating more high-quality video guides. Subscribe

Provide feedback

Saved searches

Use saved searches to filter your results more quickly

Sign up

See Also:
DataGridViewRow Members

Syntax

[System.ComponentModel.TypeConverter(typeof(System.Windows.Forms.DataGridViewRowConverter))]
public class DataGridViewRow : DataGridViewBand

Remarks

The System.Windows.Forms.DataGridViewRow class represents a row in a System.Windows.Forms.DataGridView control. You can retrieve rows through the DataGridView.Rows and DataGridView.SelectedRows collections of the control.

Unlike a System.Windows.Forms.DataGridViewColumn, a System.Windows.Forms.DataGridViewRow physically contains a collection of all of the cells in that row. You can access this collection through the DataGridViewRow.Cells property.

The System.Windows.Forms.DataGridViewRow class is used to access the individual cell elements, as well as to adjust the appearance and behavior of the row user interface (UI), such as height and cell style. Typically, you will want all rows or most rows in the control to share the same characteristics. To set cell styles for all rows in the control, set the properties of the object returned by the DataGridView.RowsDefaultCellStyle property. To set styles for alternating rows, use the DataGridView.AlternatingRowsDefaultCellStyle property. For more information about cell styles, see Cell Styles in the Windows Forms DataGridView Control. You can also use the DataGridView.RowTemplate property to define a row that will be used as a basis for all rows added to the control.

The System.Windows.Forms.DataGridView control will share System.Windows.Forms.DataGridViewRow objects across multiple data rows whenever possible to avoid performance penalties. Unless you are working with large amounts of data and experiencing performance issues, you can typically ignore row sharing. A shared row is indicated by an DataGridViewBand.Index property value of -1. Some members of the System.Windows.Forms.DataGridViewRow class cannot be used with shared rows, but you can unshare a row by accessing it through the DataGridViewRowCollection.Item(int) property. Rows can also become unshared in other ways. To access a row without unsharing it, use the DataGridViewRowCollection.SharedRow(int) method. When working with large amounts of data, you should be aware of how rows are shared and unshared to avoid performance penalties. For more information, see Best Practices for Scaling the Windows Forms DataGridView Control.

Requirements

Namespace: System.Windows.Forms
Assembly: System.Windows.Forms (in System.Windows.Forms.dll)
Assembly Versions: 2.0.0.0
Since: .NET 2.0

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 ();
   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 {
    if (dataGridView1.CurrentCell == null) return;
    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 (12 Кб)

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

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

 Разработка базового редактора несвязанной таблицы на основе DataGridView (файл .pdf) (483 Кб)

 Проект C# (Visual Studio 2019) из статьи .pdf, развернуть архив .zip в новую папку (12 Кб)

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


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

Понравилась статья? Поделить с друзьями:
0 0 голоса
Рейтинг статьи
Подписаться
Уведомить о
guest

0 комментариев
Старые
Новые Популярные
Межтекстовые Отзывы
Посмотреть все комментарии
  • Обои на рабочий стол темный фон windows
  • Код ошибки 0x80004005 windows 7 блютуз
  • Резервные файлы реестра windows 10
  • Как на windows xp установить microsoft office 2007
  • Оболочки для windows media player