Практическое руководство. Привязка данных к элементу управления DataGridView в Windows Forms
Элемент управления DataGridView поддерживает стандартную модель привязки данных Windows Forms, допускающую привязку к разнообразным источникам данных. Обычно выполняется привязка к объекту BindingSource, который управляет взаимодействием с источником данных. Компонент BindingSource может быть любым источником данных Windows Forms, что обеспечивает большую гибкость при выборе или изменении расположения данных. Дополнительные сведения об источниках данных, поддерживаемых элементом управления DataGridView, см. в разделе Общие сведения об элементе управления DataGridView.
Visual Studio имеет обширную поддержку привязки данных к элементу управления DataGridView. Дополнительные сведения см. в статье Практическое руководство. Привязка данных к элементу управления DataGridView в Windows Forms с помощью конструктора.
Подключение элемента управления DataGridView к данным
- Реализуйте метод, обрабатывающий получение данных. В примере кода ниже реализован метод GetData , инициализирующий компонент SqlDataAdapter и использующий его для заполнения DataTable. Затем он привязывает DataTable к BindingSource.
- В обработчике событий Load формы привяжите элемент управления DataGridView к компоненту BindingSource и вызовите метод GetData для получения данных.
Пример
Этот полный пример кода извлекает данные из базы данных для заполнения элемента управления DataGridView в форме Windows. Форма также содержит кнопки для повторной загрузки данных и отправки изменений в базу данных.
Для этого примера требуются:
- доступ к примеру базы данных Northwind. Дополнительные сведения об установке примера базы данных Northwind см. в разделе Получение примеров баз данных для примеров кода ADO.NET;
- ссылки на сборки System, System.Windows.Forms, System.Data и System.Xml.
Чтобы выполнить сборку и запуск этого примера, вставьте код в файл кода Form1 в новом проекте Windows Forms. Сведения о сборке из командной строки C# или Visual Basic см. в разделах Сборка из командной строки с помощью csc.exe или Сборка из командной строки.
Заполните переменную connectionString в примере значениями для подключения к примеру базы данных Northwind на SQL Server. Проверка подлинности Windows, также называемая встроенной безопасностью, является более безопасным способом подключения к базе данных, чем хранение пароля в строке подключения. Дополнительные сведения о безопасности подключений см. в разделе Защита сведений о подключении.
using System; using System.Data; using System.Data.SqlClient; using System.Globalization; using System.Windows.Forms; namespace WindowsFormsApp < public partial class Form1 : Form < public Form1() < InitializeComponent(); >> > public class Form1 : Form < private DataGridView dataGridView1 = new DataGridView(); private BindingSource bindingSource1 = new BindingSource(); private SqlDataAdapter dataAdapter = new SqlDataAdapter(); private Button reloadButton = new Button(); private Button submitButton = new Button(); [STAThread()] public static void Main() < Application.Run(new Form1()); >// Initialize the form. public Form1() < dataGridView1.Dock = DockStyle.Fill; reloadButton.Text = "Reload"; submitButton.Text = "Submit"; reloadButton.Click += new EventHandler(ReloadButton_Click); submitButton.Click += new EventHandler(SubmitButton_Click); FlowLayoutPanel panel = new FlowLayoutPanel < Dock = DockStyle.Top, AutoSize = true >; panel.Controls.AddRange(new Control[] < reloadButton, submitButton >); Controls.AddRange(new Control[] < dataGridView1, panel >); Load += new EventHandler(Form1_Load); Text = "DataGridView data binding and updating demo"; > private void GetData(string selectCommand) < try < // Specify a connection string. // Replace with the SQL Server for your Northwind sample database. // Replace "Integrated Security=True" with user login information if necessary. String connectionString = "Data Source=;Initial Catalog=Northwind;" + "Integrated Security=True"; // Create a new data adapter based on the specified query. dataAdapter = new SqlDataAdapter(selectCommand, connectionString); // Create a command builder to generate SQL update, insert, and // delete commands based on selectCommand. SqlCommandBuilder commandBuilder = new SqlCommandBuilder(dataAdapter); // Populate a new data table and bind it to the BindingSource. DataTable table = new DataTable < Locale = CultureInfo.InvariantCulture >; dataAdapter.Fill(table); bindingSource1.DataSource = table; // Resize the DataGridView columns to fit the newly loaded content. dataGridView1.AutoResizeColumns( DataGridViewAutoSizeColumnsMode.AllCellsExceptHeader); > catch (SqlException) < MessageBox.Show("To run this example, replace the value of the " + "connectionString variable with a connection string that is " + "valid for your system."); >> private void Form1_Load(object sender, EventArgs e) < // Bind the DataGridView to the BindingSource // and load the data from the database. dataGridView1.DataSource = bindingSource1; GetData("select * from Customers"); >private void ReloadButton_Click(object sender, EventArgs e) < // Reload the data from the database. GetData(dataAdapter.SelectCommand.CommandText); >private void SubmitButton_Click(object sender, EventArgs e) < // Update the database with changes. dataAdapter.Update((DataTable)bindingSource1.DataSource); >>
Imports System.Data.SqlClient Imports System.Windows.Forms Public Class Form1 Inherits Form Private dataGridView1 As New DataGridView() Private bindingSource1 As New BindingSource() Private dataAdapter As New SqlDataAdapter() Private WithEvents ReloadButton As New Button() Private WithEvents SubmitButton As New Button() Public Shared Sub Main() Application.Run(New Form1()) End Sub ' Initialize the form. Public Sub New() dataGridView1.Dock = DockStyle.Fill ReloadButton.Text = "Reload" SubmitButton.Text = "Submit" Dim panel As New FlowLayoutPanel With < .Dock = DockStyle.Top, .AutoSize = True >panel.Controls.AddRange(New Control() ) Controls.AddRange(New Control() ) Text = "DataGridView data binding and updating demo" End Sub Private Sub GetData(ByVal selectCommand As String) Try ' Specify a connection string. ' Replace with the SQL Server for your Northwind sample database. ' Replace "Integrated Security=True" with user login information if necessary. Dim connectionString As String = "Data Source=;Initial Catalog=Northwind;" + "Integrated Security=True;" ' Create a new data adapter based on the specified query. dataAdapter = New SqlDataAdapter(selectCommand, connectionString) ' Create a command builder to generate SQL update, insert, and ' delete commands based on selectCommand. Dim commandBuilder As New SqlCommandBuilder(dataAdapter) ' Populate a new data table and bind it to the BindingSource. Dim table As New DataTable With < .Locale = Globalization.CultureInfo.InvariantCulture >dataAdapter.Fill(table) bindingSource1.DataSource = table ' Resize the DataGridView columns to fit the newly loaded content. dataGridView1.AutoResizeColumns( DataGridViewAutoSizeColumnsMode.AllCellsExceptHeader) Catch ex As SqlException MessageBox.Show("To run this example, replace the value of the " + "connectionString variable with a connection string that is " + "valid for your system.") End Try End Sub Private Sub Form1_Load(ByVal sender As Object, ByVal e As EventArgs) _ Handles Me.Load ' Bind the DataGridView to the BindingSource ' and load the data from the database. dataGridView1.DataSource = bindingSource1 GetData("select * from Customers") End Sub Private Sub ReloadButton_Click(ByVal sender As Object, ByVal e As EventArgs) _ Handles ReloadButton.Click ' Reload the data from the database. GetData(dataAdapter.SelectCommand.CommandText) End Sub Private Sub SubmitButton_Click(ByVal sender As Object, ByVal e As EventArgs) _ Handles SubmitButton.Click ' Update the database with changes. dataAdapter.Update(CType(bindingSource1.DataSource, DataTable)) End Sub End Class
См. также
- DataGridView
- DataGridView.DataSource
- BindingSource
- Отображение данных в элементе управления DataGridView в Windows Forms
- Защита сведений о подключении
Совместная работа с нами на GitHub
Источник этого содержимого можно найти на GitHub, где также можно создавать и просматривать проблемы и запросы на вытягивание. Дополнительные сведения см. в нашем руководстве для участников.
Пошаговое руководство. Отображение данных из базы данных SQL Server в элементе управления DataGrid
В этом пошаговом руководстве выполняется получение данных из базы данных SQL Server и их отображение в элементе управления DataGrid. С помощью ADO.NET Entity Framework можно создавать классы сущностей, представляющих данные, и использовать LINQ для записи запроса, который выполняет получение указанных данных из класса сущности.
Необходимые компоненты
Для выполнения этого пошагового руководства требуются следующие компоненты:
- Visual Studio.
- Доступ к запущенному экземпляру SQL Server или SQL Server Express с подключенной учебной базой данных AdventureWorks. Базу данных AdventureWorks можно загрузить из GitHub.
Создание новых классов сущностей
- Создайте проект приложения WPF на Visual Basic или C# с именем DataGridSQLExample .
- В обозревателе решений щелкните проект правой кнопкой мыши, выберите сначала Добавить, а затем Новый элемент. Откроется диалоговое окно Добавление нового элемента.
- В области «Установленные шаблоны» выберите Данные и в списке шаблонов выберите ADO.NET EDM (модель данных с использованием сущностей).

- Назовите файл AdventureWorksModel.edmx , а затем щелкните Добавить. Появится мастер модели EDM.
- На экране «Выбор содержимого модели» выберите Конструктор EF из базы данных, а затем нажмите кнопку Далее.
- На экране «Выбор подключения к данным» укажите подключение к базе данных AdventureWorksLT2008. Дополнительные сведения см. в статье Диалоговое окно «Выбор подключения к данным». Проверьте, чтобы имя было AdventureWorksLT2008Entities и чтобы был установлен флажок у параметра Сохранить параметры соединения сущности в App.Config как:, после чего нажмите Далее.
- На экране «Выбор объектов базы данных» разверните узел «Таблицы» и выберите таблицы Product и ProductCategory. Вы можете создавать классы сущностей для всех таблиц; однако в этом примере данные извлекаются только из этих двух таблиц.

- Нажмите кнопку Готово. Сущности Product и ProductCategory отображаются в конструкторе сущностей.

Получение и представление данных
- Откройте файл MainWindow.xaml.
- Задайте для свойства Width элемента Window значение 450.
- В редакторе XAML добавьте следующий тег DataGrid между тегами
и , чтобы добавить элемент DataGrid с именем dataGrid1 .

Примечание. Если используется Visual Basic, в первой строке MainWindow.xaml замените x:Class=»DataGridSQLExample.MainWindow» на x:Class=»MainWindow» .
using System.Data.Entity.Core.Objects; using System.Linq; using System.Windows; namespace DataGridSQLExample < /// /// Interaction logic for MainWindow.xaml /// public partial class MainWindow : Window < AdventureWorksLT2008Entities dataEntities = new AdventureWorksLT2008Entities(); public MainWindow() < InitializeComponent(); >private void Window_Loaded(object sender, RoutedEventArgs e) < var query = from product in dataEntities.Products where product.Color == "Red" orderby product.ListPrice select new < product.Name, product.Color, CategoryName = product.ProductCategory.Name, product.ListPrice >; dataGrid1.ItemsSource = query.ToList(); > > >
Imports System.Data.Objects Class MainWindow Dim dataEntities As AdventureWorksLT2008Entities = New AdventureWorksLT2008Entities Private Sub Window_Loaded(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs) Handles MyBase.Loaded Dim products As ObjectQuery(Of Product) = dataEntities.Products Dim query = _ From product In products _ Where product.Color = "Red" _ Order By product.ListPrice _ Select product.Name, product.Color, CategoryName = product.ProductCategory.Name, product.ListPrice dataGrid1.ItemsSource = query.ToList() End Sub End Class

См. также
Совместная работа с нами на GitHub
Источник этого содержимого можно найти на GitHub, где также можно создавать и просматривать проблемы и запросы на вытягивание. Дополнительные сведения см. в нашем руководстве для участников.
Вопросы с меткой [datagridview]
DataGridView — это элемент управления, позволяющий отображать данные в табличном формате, в настраиваемой сетке.
409 вопросов
Конкурсные
Неотвеченные
- Конкурсные 0
- Неотвеченные
- Цитируемые
- Рейтинг
- Неотвеченные (мои метки)
Открыть таблицу DataGridView с ComboBox из файла
Есть таблица с учениками, номерами занятий и оценками. (Оценки выставляются из коллекции комбобоксов). Сохраняется это всё таким образом (работает идеально): private void button6_Click(object sender, .
задан 27 фев 2023 в 20:21
205 показов
В dataGridView не получается вывести элементы массива C#
сообщество! Я ещё студент и имею немного опыта в WinForms, нужно по заданию сгенерировать массив из N количества случайных чисел (одномерный массив) в элемент dataGridView. При попытке сгенерировать — .
задан 9 фев 2023 в 12:32
87 показов
Вывести данные в datagridview EF Core
Здравствуйте, подскажите пжлст, хочу вывести данные из БД в datagridview , но после запуска datagridview пустой, ошибок нет, привожу данные к типу List . но не работает/ошибку не выдаёт. И ещё .
задан 3 фев 2023 в 19:34
45 показов
Как сделать фильтрацию данных в DataGridView в WinForms
Есть ComboBox с данными коллекции департаментов. Есть DataGridView с данными коллекции рабочих. Нужно, чтобы при выборе департамента в ComboBox, DataGridView отображал только тех рабочих, которые .
задан 23 янв 2023 в 21:04
Как заполнить из массива сразу несколько столбцов в DataGridView через DataSource?
Пытаюсь заполнить сразу несколько столбцов строками в DataView через DataSource. Удалось заполнить только один — код ниже. Интересно, как работает DataSource в данном случае, почему просто не .
задан 8 янв 2023 в 16:01
30 показов
Как заменить значения в строках DataGridView из автоматически сгенерированных на свои?
Кому не сложно, подскажите такой момент: есть DataGridView, столбцы которого создаются в коде. dataGridView1.Columns.AddRange( new DataGridViewTextBoxColumn() < Name = "clmID", .
задан 26 дек 2022 в 15:53
106 показов
Как быстрее всего заполнить DataTable (для DataGridView)?
Конкретным новичком себя назвать не могу, раньше уже с С# дело имела, как и с DataGridView (дальше DGV), но раньше до скорости загрузки данных дела не было (данных было мало, да и сами БД по структуре .
задан 25 дек 2022 в 12:41
55 показов
В чем ошибка фильтрации диапазона дат DataGridView SQLite?
На форме таблицы оценок нужно сделать фильтрацию по дате. Есть два DateTimePicker — стартовое и конечное значение даты. Сначала создается такая же таблица как без фильтрации, затем проходиться циклом .
задан 9 дек 2022 в 12:52
c# datagridview не сохраняет без enter
DataGridView почему то отправляет данные в БД (MS Server), только если я при вводе в табличку (при ее изменение) нажимал на Enter или если я через button update табличку. Как сделать чтобы без нажатий .
задан 29 ноя 2022 в 22:11
38 показов
Почему LINQ ищет только то что указано в одном блоке if а всё остальное нет
Приветсвую! Проблема с LINQ! Не понимаю почему он ищет только минимальный элемент а максимальный искать отказывается(это проявляется в том что таблица dataGridView не изменяеться Вот код private void .
задан 29 ноя 2022 в 19:17
Как отобразить данные в dataGridView после осуществления поиска LINQ
Перейду сразу к сути дела! Есть dataGridView, в нем изначально отображены продукты(в моем случае это еда из макдональдса по типу наггетсов, бургеров и прочего). В этом отображении показана информация .
задан 28 ноя 2022 в 10:41
58 показов
Как реализовать поиск с помощью LINQ в dataGridView?
Здраствуйте! Возникла проблема с поиском с использованием LINQ в элементе управления dataGridView В него добавлены товары. товар описан как класс. Он реализуется вот так: public class Product < .
задан 27 ноя 2022 в 18:50
Почему не работает проверка добавления в DataGridView при существовании такого же поля
Нужно создать проверку добавления или изменения учебного предмета. Если введенное название и класс уже есть то должна срабатывать ошибка, чего не происходит :c Вот сама проверка: public static bool .
задан 26 ноя 2022 в 17:37
57 показов
C# Вывод даных в datagridview с другого потока
Подскажите, в чем может быть проблема. Есть класс «NetworkModel» в котором, создается поток для прослушивания сокета, и данные которые приходят необходимо вывести в таблицу, которая .
задан 15 ноя 2022 в 9:40
240 показов
Как сортировать DataGridView программно
Ребят, подскажите, пожалуйста, в какую сторону копать или что можно использовать. Мне нужно отсортировывать столбцы таблицы dataGridView, но проблема в том, что стандартная встроенная сортировка мне .
задан 19 окт 2022 в 13:42
15 30 50 на странице
-
Важное на Мете
Связанные метки
Подписаться на ленту
Лента новых вопросов с меткой [datagridview]
Для подписки на ленту скопируйте и вставьте эту ссылку в вашу программу для чтения RSS.
Дизайн сайта / логотип © 2024 Stack Exchange Inc; пользовательские материалы лицензированы в соответствии с CC BY-SA . rev 2024.1.9.3159
Нажимая «Принять все файлы cookie» вы соглашаетесь, что Stack Exchange может хранить файлы cookie на вашем устройстве и раскрывать информацию в соответствии с нашей Политикой в отношении файлов cookie.
DataGridView управление базой данных

Под управлением базой данных в приложении понимается редактирование, вставка и удаления строк. Прилагаемое приложение позволяет редактировать содержимое базы данных в режиме «Что вижу, то и получаю» (технология WYSIWYG).
Исполняющие методы-события унифицированы для редактируемых визуальных элементов DataGridView. Процедура вставки новой строки и редактирование существующей включает практически одинаковые действия. Процесс удаления строк имеет логику отмены действия. Источники данных для элементов DataGridView — это объекты типа BindingSource, которые взаимодействуют с базой данных посредством одного экземпляра DataSet.
Программный код приложения управления базой данных содержит немного добавочных строк, основная логика построена на уже заложенной в DataGridView функциональности. В приложении программно реализованы отношения между таблицами и ограничения Foreign Key, Unique.
Формирование интерфейса DataGridView
Интерфейс приложения построен на трёх элементах DataGridView. В качестве источника данных для элементов отображения таблиц в приложении применены объекты типа BindingSource. Использование класса BindingSource обеспечивает приложению взаимосвязанные манипуляции с таблицами данных.
Первый элемент DataGridView отображает таблицу Types типов продуктов. Второй элемент использует источник данных первого элемента и показывает временную таблицу выборки продуктов определенного типа. Третий элемент выводит всю таблицу продуктов Products .
В свою очередь объекты BindingSource, получают данные из базы посредством одного экземпляра DataSet. Заполнение DataSet возможно двумя способами.
Метод формирования интерфейса элементов отображения таблиц. В таблицы добавляются столбцы типа DataGridViewComboBoxColumn для отображения имени типа вместо числового идентификатора.
void BindDataSource(DataSet ds, DataGridView dgvParent, DataGridView dgvDetail, DataGridView dgvChild) < // === Создание функционального интерфейса элемента DataGridView === // Источники данных для DataGridView. BindingSource parent = new(); BindingSource detail = new(); BindingSource child = new(); // Редактируемая таблица типов, родительская для таблицы Product. parent.DataSource = ds; parent.DataMember = Constants.ParentTableName; // Заголовок с названием текущей таблицы. groupBoxParent.Text = "Таблица """ + Constants.ParentTableName + """"; // Таблица просмотра продуктов выбранного типа. detail.DataSource = parent; // Отображаем таблицу в соответствии с выбранным внешним ключом. detail.DataMember = "FK_Product_Type"; groupBoxDetail.Text = "Продукты выбранного типа"; // Редактируемая таблица Product child.DataSource = ds; child.DataMember = Constants.ChildTableName; // Связывание источников данных с элементами управления // для отображения соответствующих таблиц. dgvParent.DataSource = parent; dgvDetail.DataSource = detail; dgvChild.DataSource = child; // Видимость столбцов в завизимости от конфигурации решения. // Невидимость столбца идентификаторов. // Для удобства созданы порядковые номера в заголовках строк. // Идентификаторы внешних ключей скрываются, // остаются только названия типов. #if DEBUG == false dgvParent.Columns["Id"].Visible = false; dgvDetail.Columns["Id"].Visible = false; dgvChild.Columns["Id"].Visible = false; dgvDetail.Columns["TypeId"].Visible = false; dgvChild.Columns["TypeId"].Visible = false; #endif //===Таблица выбранного типа === // Вставка столбца НазваниеТипа в таблицу выбранного типа DataGridViewComboBoxColumn colbox2 = new(); colbox2.Name = "TypeName"; // Таким кодом активизируется связь между родительской таблицей и // дочерней для отображения в элементах DataGridView. colbox2.DataSource = parent; // Так связи не будет. // colbox.DataSource = ds.Tables["Type"]; colbox2.DisplayMember = "Name"; colbox2.ValueMember = "Id"; colbox2.DataPropertyName = "TypeId"; colbox2.DisplayIndex = 1; colbox2.FlatStyle = FlatStyle.Flat; // Если закомментировать строку ниже у ячеек DataGridViewComboBoxColumn // появится кнопка вызова списка. colbox2.DisplayStyle = DataGridViewComboBoxDisplayStyle.Nothing; dgvDetail.Columns.Add(colbox2); // ==== // === Таблица Product === // Отображение названия таблицы. groupBoxChild.Text = "Таблица """ + Constants.ChildTableName + """"; // Добавление способа установки типа продукта по имени. DataGridViewComboBoxColumn colbox = new(); colbox.Name = "TypeName"; // Таким кодом активизируется связь между родительской таблицей и // дочерней в текущем DataGridView. colbox.DataSource = parent; colbox.DisplayMember = "Name"; colbox.ValueMember = "Id"; colbox.DataPropertyName = "TypeId"; colbox.DisplayIndex = 1; colbox.FlatStyle = FlatStyle.Flat; colbox.SortMode = DataGridViewColumnSortMode.Automatic; // Если закомментировать строку ниже у ячеек DataGridViewComboBoxColumn // появится кнопка вызова списка. colbox.DisplayStyle = DataGridViewComboBoxDisplayStyle.Nothing; dgvChild.Columns.Add(colbox); // === >
Наполнение DataSet данными
В приложении есть два варианта получения данных из базы в объект DataSet. Оба способа работают одинаково, но второй позволяет немного упростить программный код.
Первый способ, классический, DataSet заполняется методом SqlDataAdapter.Fill(. ) . Таким способом объект DataSet не получает из базы свойства IDENTITY (AUTO_INCREMENT) первичных ключей, названия таблиц, значения NOT NULL и другое. Для соответствия имен таблиц исходным в базе данных дополнительно необходима карта сопоставления названий таблиц.
Второй способ основан на получение данных через SqlDataReader в виде списка таблиц. В этом случае таблицы получают не только данные, но и основную информацию о своих схемах, кроме отношений и ограничений Foreign Key. Возможно в будущем более полная информация будет передаваться в таблицы: современные базы данных выдают любые схемо-сведения .
public static DataSet FillDataAdapter(string querystring, List? parameters = null) < using SqlConnection connection = new(ConnectionString); SqlDataAdapter adapter = GetAdapter(connection, querystring, parameters); DataSet dataSet = new("Catalog"); // Карта сопоставления названий таблиц набора DataSet и базы данных. adapter.TableMappings.Add("Table", Constants.ParentTableName); adapter.TableMappings.Add("Table1", Constants.ChildTableName); adapter.Fill(dataSet); return dataSet; >public static DataSet FillDataReader(string querytext, List? parameters = null) < using SqlConnection connection = new(ConnectionString); // C# 9.0 using SqlCommand command = new(querytext, connection); // C# 9.0 if (parameters != null) < foreach (SqlParameter p in parameters) < command.Parameters.Add(p); >> connection.Open(); List tables = new(); // Получаем многие данные таблиц, в т.ч. и название таблиц автоматически. // Получаем: свойства автоинкремент первичного ключа, свойства столбцов // NOT NULL и др. SqlDataReader reader = command.ExecuteReader(CommandBehavior.KeyInfo); while (reader.IsClosed == false) < DataTable table = new(); table.Load(reader); tables.Add(table); >DataSet dataSet = new DataSet("Catalog"); // Добавление таблиц в коллекцию набора. foreach (DataTable dt in tables) < dataSet.Tables.Add(dt); >return dataSet; > public static void SaveData(DataTable dt, string querystring, List? parameters = null) < using SqlConnection connection = new(ConnectionString); SqlDataAdapter adapter = GetAdapter(connection, querystring, parameters); // Для обновления передаётся таблица. // adapter.Update обновляет базу данных по таблично. // Чтобы не передавать в данный метод два параметра: // DataSet и название таблицы, передаётся один параметр DataTable // с названием таблицы внутри. int i = adapter.Update(dt); // Звук успешного обновления - для режима тестирования. #if DEBUG if (i >0) Console.Beep(3000, 100); #endif > // Метод формирует разный код в зависимости от // способа получения данных. void SetRelationConstraint(DataSet ds, bool isdataadapter) < DataTable parentTable = ds.Tables[Constants.ParentTableName]; DataTable childTable = ds.Tables[Constants.ChildTableName]; // Определение отношений между таблицами. // В базе данных эти отношения не определены. DataColumn parentColumn = parentTable.Columns["Id"]; DataColumn childColumn = childTable.Columns["TypeId"]; . . . // Код необходим только при заполнении DataSet с помощью SqlDataAdapter. // Если заполнение DataSet построить на DataTable этот код не требуется. if (isdataadapter == true) < // Установка свойства автонумерации идентификаторов. DataColumn columnId = parentColumn; columnId.AutoIncrement = true; columnId.ReadOnly = true; DataColumn columnId2 = childTable.Columns["Id"]; columnId2.AutoIncrement = true; columnId2.ReadOnly = true; // Вручную устанавливаем запрет NULL. // Если заполнение DataSet построить на DataTable эта строка не потребуется. parentTable.Columns["Name"].AllowDBNull = false; childTable.Columns["SKU"].AllowDBNull = false; >>
Вставка новой строки
Метод события DataGridView.RowEnter() в приложении начинает процедуру создания новой строки. Данное событие генерируется в момент получения фокуса любой строкой элемента управления DataGridView. Строки в приложении могут добавляться только по одной штуке.
При получении фокуса самой нижней строкой, предназначенной для формирования новой строки, в ячейку идентификатора записывается значение, которое гарантированно не совпадает с любым значением первичного ключа. Далее в необходимые ячейки вводятся значения.
После окончания редактирования новой строки перевод фокуса на любую другую строку вызывает событие DataGridView.RowValidated() , новая строка помечается как AddedRow и далее записывается в базу данных.
Одновременно с записью новой строки из базы данных запрашивается ее идентификатор, которым перезаписывается временное значение первичного ключа. Это очень важное мероприятие: без синхронизации первичных ключей таблиц элементов DataGridView и таблиц базы данных возможно нежелательное удаление или перезаписывание важной информации.
private void RowEnter(object sender, DataGridViewCellEventArgs e) < // === Программный код участия в создании новой строки. DataGridView dgv = (DataGridView)sender; // Пока новая строка не добавлена в таблицу источника данных, // её неизвестен идентификатор. if (dgv.Rows[e.RowIndex].IsNewRow == true) < dgv.Rows[e.RowIndex].Cells["Id"].Value = "-1"; >> private void RowValidated(object sender, DataGridViewCellEventArgs e) < // Запись изменений в базу данных. Запросы UPDATE, INSERT, // исключая DELETE. DataGridView dgv = (DataGridView)sender; BindingSource bs = (BindingSource)dgv.DataSource; // Получение ссылки на редактируемую часть источника данных. DataSet ds = (DataSet)bs.DataSource; string tablename = bs.DataMember; // Сохранение в базу данных изменений и вставок строк. SaveModifications(ds, tablename); // Погашение текста и иконки ошибок связанных с ячейками. foreach (DataGridViewCell cell in dgv.Rows[e.RowIndex].Cells) < cell.ErrorText = null; >> // Логика записи UPDATE, INSERT в базу данных. void SaveModifications(DataSet ds, string tablename) < DataTable? dt = ds.Tables[tablename]; if (dt != null && ds.HasChanges() == true) < if (ds.HasChanges(DataRowState.Added) == true) InsertRow(dt); if (ds.HasChanges(DataRowState.Modified) == true) UpdateRow(dt); >> // Метод записи SQL запроса INSERT в базу данных. void InsertRow(DataTable dt) < string tablename = dt.TableName; // Получаем ссылку на новую строку. DataRow? row = dt.AsEnumerable().FirstOrDefault(r =>r.RowState == DataRowState.Added); if (row == null) return; List parameters = new(); List listnames = new(); List listvalues = new(); // Формирование списков имен и значений столбцов. int count = 0; foreach (DataColumn col in row.Table.Columns) < // В столбец со свойством идентификатора IDENTITY // значения записывать нельзя. if (col.AutoIncrement == false) < listnames.Add("[" + col.ColumnName + "]"); SqlParameter parUri = new() < // Конвертирует в необходимый тип автоматически, // без явного указания типа. //DbType = , Direction = ParameterDirection.Input, ParameterName = "Param" + count, Value = row[col.ColumnName] >; parameters.Add(parUri); count++; listvalues.Add("@" + parUri.ParameterName); > > string names = string.Join(',', listnames); string values = string.Join(',', listvalues); // Ожидаемый идентификатор вставленной строки. SqlParameter lastId = new() < Direction = ParameterDirection.Output, ParameterName = "Identity", Size = 8 >; parameters.Add(lastId); // Одновременно со вставкой строки получаем ее идентификатор // с целью синхронизации ключей элемента DataGridView и базы данных. string queryString = "INSERT INTO " + tablename + " (" + names + ") VALUES(" + values + ");"; // Функция IDENT_CURRENT( 'table_or_view' ) возвращает // последнее значение идентификатора для указанной таблицы. queryString += "SET @Identity = IDENT_CURRENT('" + tablename + "');"; //queryString += "SELECT @Identity=IDENT_CURRENT ('Product');"; ConnectDatabase.SaveData(dt, queryString, parameters); // Идентификатор новой строки получает актуальное значение. dt.Columns["Id"]!.ReadOnly = false; row["Id"] = lastId.Value; dt.Columns["Id"]!.ReadOnly = true; // Принятие изменений после присвоения настоящего идентификатора строки. // иначе логика SqlDataAdapter.Update() будет думать что это модификация строки и // без необходимости перезапишет эту строку в базе данных. row.AcceptChanges(); >
Редактирование строки
Логическая процедура похожа на последовательность вставки строки: получение фокуса строки — событие RowEnter() , редактирование ячеек, перевод фокуса — событие RowValidated() .
Редактирование строк заключается в изменении значений заполненных ячеек или добавлении значений в пустые ячейки таблиц элемента управления DataGridView.
После окончания редактирования строки переводом фокуса вызывается событие DataGridView.RowValidated(), отредактированная строка помечается как ModifiedRow и сохраняется в базу данных.
Метод записи изменённых и новых значений строки в базу данных, выполнение SQL запроса UPDATE . Программный код методов событий смотрите выше.
void UpdateRow(DataTable dt) < string tablename = dt.TableName; // Получение ссылки на изменённую строку. DataRow? row = dt.AsEnumerable().FirstOrDefault(r =>r.RowState == DataRowState.Modified); if (row == null) return; List parameters = new(); List listnamesvalues = new(); object int count = 0; foreach (DataColumn col in row.Table.Columns) < string columnname = col.ColumnName; object value = row[col.ColumnName]; // Идентификатор нельзя перезаписывать. if (col.AutoIncrement == false) < SqlParameter parUri = new() < // Конвертирует в необходимый тип автоматически, // без явного указания типа. //DbType = , Direction = ParameterDirection.Input, ParameterName = "Param" + count, Value = row[col.ColumnName] >; parameters.Add(parUri); count++; // Полуфабрикат [имя]=значение. для строки запроса. listnamesvalues.Add("[" + col.ColumnName + "]=@" + parUri.ParameterName); > > // Идентификатор модифицированной строки // передаётся посредством параметра. SqlParameter < Direction = ParameterDirection.Input, ParameterName = "Identity", Value = id >; parameters.Add(Id); string namesvalues = string.Join(',', listnamesvalues); string queryString = "UPDATE " + tablename + " SET " + namesvalues + " WHERE ConnectDatabase.SaveData(dt, queryString, parameters); >
Удаление строк
Чтобы удалить строки из базы, необходимо их выделить и нажать клавишу DELETE. Программная последовательность удаления строк включает три события:
DataGridView.KeyDown() – обеспечивает диалоговый интерфейс подтверждения или отмены процедуры удаления строк.
DataGridView.UserDeletingRow() – программная логика отмены процедуры удаления строк.
DataGridView.RowsRemoved() – удаляемые строки уже помечены как DeletedRow и передаются в метод удаления из базы данных.
private void DGVKeyDown(object sender, KeyEventArgs e) < // === Интерфейс диалога удаления и отмены удаления строк === DataGridView dgv = (DataGridView)sender; BindingSource bs = (BindingSource)dgv.DataSource; DataSet ds = (DataSet)bs.DataSource; string tablename = bs.DataMember; if (e.KeyCode == Keys.Delete) < if (ds != null) < int numberrowsdelete = dgv.SelectedRows.Count; DataTable? dt = ds.Tables[tablename]; if (dt != null) < // Внешний флаг удаления строк для переноса решения в другой метод. // По умолчанию запрещаем удаление строк. _deleteRows = false; if (MessageBox.Show( "Удалить строки? Количество - " + numberrowsdelete, "Удаление строк!", MessageBoxButtons.YesNo, MessageBoxIcon.Exclamation) == DialogResult.Yes) < // Удаление разрешено. _deleteRows = true; >> > > . . . > private void UserDeletingRow(object sender, DataGridViewRowCancelEventArgs e) < // === Логика отмены удаления строк === // true - отмена действия, false - продолжения действия. e.Cancel = !_deleteRows; >private void RowsRemoved(object sender, DataGridViewRowsRemovedEventArgs e) < // === Непосредственное удаление строк === DataGridView dgv = (DataGridView)sender; BindingSource bs = (BindingSource)dgv.DataSource; DataSet ds = (DataSet)bs.DataSource; string tablename = bs.DataMember; DataTable? dt = ds.Tables[tablename]; if (dt != null) < DeleteRows(dt); >> void DeleteRows(DataTable dt) < string tablename = dt.TableName; // Получение строк помеченных для удаления. DataRow? row = dt.AsEnumerable().FirstOrDefault(r =>r.RowState == DataRowState.Deleted); if (row != null) < // Получение идентификатора удаленной строки. string? DataRowVersion.Original].ToString(); if (id == null) return; // Удаляем строку из базы по её идентификатору. string queryString = "DELETE FROM " + tablename + " WHERE ;"; ConnectDatabase.SaveData(dt, queryString); >>
Порядковые номера строк
Первичные ключи таблиц базы данных имеют свойство IDENTITY (для MySQL AUTO_INCREMENT) и равными шагами увеличиваются после вставки новой строки. Но равномерность нарушается при удалении строк и для пользователей не очень логично выглядят такие значения.
Для комфорта пользователей в строковых заголовочных ячейках вставляются порядковые номера строк, а столбцы с идентификаторами скрываются. Обновление порядковых номеров происходит после подключения источника данных и при изменениях его содержимого.
В таблице элемента DataGridView, связанным с источником данных, изменить значения в заголовках строк можно только после завершения привязки. Поэтому вычисление и вставка номеров происходит в событии DataGridView.DataBindingComplete() .
private void DataBindingComplete(object sender, DataGridViewBindingCompleteEventArgs e) < // Это событие возникает при подключении источника данных и // при изменении его содержимого. // При элементе DataGridView связанным с источником данных, // изменить значения в заголовках строк можно // только после завершения привязки. DataGridView dgv = (DataGridView)sender; foreach (DataGridViewRow row in dgv.Rows) < // Порядковый номер не ставится в новой строке, ещё не добавленной в источник данных. if (row.IsNewRow == false) row.HeaderCell.Value = (row.Index + 1).ToString(); >>
Оповещение о несохраненных данных
При изменениях в ячейках редактируемой строки таблиц возникает событие DataGridView.CellValueChanged(). В теле метода данного события отредактированные, но не сохраненные ячейки помечаются иконкой с выплывающей подсказкой. Такое состояние может возникать в случаях редактирования пользователем нескольких ячеек одной строки, без потери фокуса строкой. Как только редактируемая строка потеряет фокус, несохранённые значения запишутся в базу данных (см. выше), а иконки оповещения исчезнут.
Программная логика оповещения о несохраненных изменениях:
private void CellValueChanged(object sender, DataGridViewCellEventArgs e) < // Заголовки строк не редактируются. if (e.ColumnIndex >= 0) < DataGridView dgv = (DataGridView)sender; // Не предназначено для новых строк (которые внизу) элемента DataGridView. if (dgv.Rows[e.RowIndex].IsNewRow == false) < // Оповещение пользователя о несохраненных значениях в ячейках. dgv.Rows[e.RowIndex]. Cells[e.ColumnIndex].ErrorText = "Есть несохраненные изменения!"; >> > private void RowValidated(object sender, DataGridViewCellEventArgs e) < . . . // Погашение текста и иконки ошибок связанных с ячейками. foreach (DataGridViewCell cell in dgv.Rows[e.RowIndex].Cells) < cell.ErrorText = null; >>
Оповещение об ошибках
Ошибки, возникающие в процессе редактирования таблиц DataGridView предупреждаются событием DataGridView.DataError() . В методе размещается простейший код диалогового оповещения для выбора дальнейших действий пользователем. Событие подключено ко всем редактируемым элементам DataGridView, вычисления владельца происходит по параметру sender.
private void DataError(object sender, DataGridViewDataErrorEventArgs e) < DataGridView dgv = (DataGridView)sender; BindingSource bs = (BindingSource)dgv.DataSource; string tablename = bs.DataMember; // Если нажать кнопку Ок ошибочное значение можно изменить, // нажатие на кнопку Отмена(Cancel) возвращает предыдущее // корректное значение. if (MessageBox.Show("Таблица " + tablename + " Ошибка: ячейка " + e.RowIndex + "x" + e.ColumnIndex + " " + e.Exception.Message, "Внимание", MessageBoxButtons.OKCancel, MessageBoxIcon.Warning) == DialogResult.OK) < e.Cancel = true; >>
Исходник приложения управления базой данных
Исходник написан на языке C#, среда программирования MS Visual Studio 2022, .NET 6. В решении приложения находится скрипт для создания базы данных. Скрипт можно также скачать на странице Relations Tables в DataSet.
Скачать исходник
Тема: «DataGridView управление базой данных»
SQL Server
Виртуальные сервера VDS
- Сервера VDS Hyper-V / KVM
- Различные версии Windows Server
- Linux — CentOS, Ubuntu Server, Debian, OpenSUSE
- Защита от DDoS атак
- Бесплатный тестовый период — 10 дней