Практическое руководство. Связывание объекта DataView с элементом управления DataGridView в Windows Forms
Элемент управления DataGridView предоставляет мощный и гибкий способ отображения данных в табличном формате. Элемент управления DataGridView поддерживает стандартную модель привязки данных Windows Forms, поэтому он выполняет привязку к DataView и другим различным источникам данных. Однако в большинстве случаев выполняется привязка к компоненту BindingSource, управляющему взаимодействием с источником данных.
Дополнительные сведения об элементе управления см. в статье Общие сведения об элементе DataGridViewуправления DataGridView.
Соединение элемента управления DataGridView с объектом DataView
- Реализуйте метод, обрабатывающий получение данных из базы данных. В следующем примере реализован метод GetData , инициализирующий компонент SqlDataAdapter и использующий его для заполнения объекта DataSet. Убедитесь, что переменной connectionString присвоено значение, соответствующее базе данных. Потребуется доступ к SQL Server с установленным образцом базы данных AdventureWorks.
private void GetData() < try < // Initialize the DataSet. dataSet = new DataSet(); dataSet.Locale = CultureInfo.InvariantCulture; // Create the connection string for the AdventureWorks sample database. string connectionString = "Data Source=localhost;Initial Catalog=AdventureWorks;" + "Integrated Security=true;"; // Create the command strings for querying the Contact table. string contactSelectCommand = "SELECT ContactID, Title, FirstName, LastName, EmailAddress, Phone FROM Person.Contact"; // Create the contacts data adapter. contactsDataAdapter = new SqlDataAdapter( contactSelectCommand, connectionString); // Create a command builder to generate SQL update, insert, and // delete commands based on the contacts select command. These are used to // update the database. SqlCommandBuilder contactsCommandBuilder = new SqlCommandBuilder(contactsDataAdapter); // Fill the data set with the contact information. contactsDataAdapter.Fill(dataSet, "Contact"); >catch (SqlException ex) < MessageBox.Show(ex.Message); >>
Private Sub GetData() Try ' Initialize the DataSet. dataSet = New DataSet() dataSet.Locale = CultureInfo.InvariantCulture ' Create the connection string for the AdventureWorks sample database. Dim connectionString As String = "Data Source=localhost;Initial Catalog=AdventureWorks;" _ & "Integrated Security=true;" ' Create the command strings for querying the Contact table. Dim contactSelectCommand As String = "SELECT ContactID, Title, FirstName, LastName, EmailAddress, Phone FROM Person.Contact" ' Create the contacts data adapter. contactsDataAdapter = New SqlDataAdapter( _ contactSelectCommand, _ connectionString) ' Create a command builder to generate SQL update, insert, and ' delete commands based on the contacts select command. These are used to ' update the database. Dim contactsCommandBuilder As SqlCommandBuilder = New SqlCommandBuilder(contactsDataAdapter) ' Fill the data set with the contact information. contactsDataAdapter.Fill(dataSet, "Contact") Catch ex As SqlException MessageBox.Show(ex.Message) End Try End Sub
private void Form1_Load(object sender, EventArgs e) < // Connect to the database and fill the DataSet. GetData(); contactDataGridView.DataSource = contactBindingSource; // Create a LinqDataView from a LINQ to DataSet query and bind it // to the Windows forms control. EnumerableRowCollectioncontactQuery = from row in dataSet.Tables["Contact"].AsEnumerable() where row.Field("EmailAddress") != null orderby row.Field("LastName") select row; contactView = contactQuery.AsDataView(); // Bind the DataGridView to the BindingSource. contactBindingSource.DataSource = contactView; contactDataGridView.AutoResizeColumns(); >
Private Sub Form1_Load(ByVal sender As System.Object, _ ByVal e As System.EventArgs) _ Handles MyBase.Load ' Connect to the database and fill the DataSet. GetData() contactDataGridView.DataSource = contactBindingSource ' Create a LinqDataView from a LINQ to DataSet query and bind it ' to the Windows forms control. Dim contactQuery = _ From row In dataSet.Tables("Contact").AsEnumerable() _ Where row.Field(Of String)("EmailAddress") <> Nothing _ Order By row.Field(Of String)("LastName") _ Select row contactView = contactQuery.AsDataView() ' Bind the DataGridView to the BindingSource. contactBindingSource.DataSource = contactView contactDataGridView.AutoResizeColumns() End Sub
См. также раздел
Практическое руководство. Привязка данных к элементу управления 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, где также можно создавать и просматривать проблемы и запросы на вытягивание. Дополнительные сведения см. в нашем руководстве для участников.
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
Хостинг для CMS
- CMS — система создания и управления сайтом
- WordPress, Joomla, Drupal и другие
- Автоматическая установка CMS
- Домен в подарок
- 10 дней бесплатного тестирования
Создание сайтов, написание приложений, программ, скриптов C++, C#, F#, PHP, JavaScript
Как заполнить datagrid данными из базы данных в имеющиеся столбцы?

добавлять удобнее в редактировании столбцов через студию, и добавьте при загрузке формы код:
InventDataGrid.AutoGenerateColumns = false;
этот не позволит создавать лишние столбцы которые не надо показывать.
Ответ написан более трёх лет назад
Комментировать
Нравится Комментировать
Ответы на вопрос 0
Ваш ответ на вопрос
Войдите, чтобы написать ответ

- C#
Как сделать метро стиль программы windows form c#?
- 1 подписчик
- 8 часов назад
- 42 просмотра

- C#
- +1 ещё
Как применить настройки прокси-сервера через реестр в С#?
- 2 подписчика
- 17 часов назад
- 136 просмотров
