Datagrid как подключить бд
Данное руководство устарело. Актуальное руководство: по ADO.NET и работе с базами данных в .NET 6
Последнее обновление: 31.10.2015
Ранее мы рассмотрели, как удобно загружать данные в приложении Windows Forms в элемент DataGridView через DataSet. Теперь определим полнофункциональную форму, через которую мы сможем производить все стандартные CRUD операции в базе данных.
Итак, определим форму, на которой будет элемент DataGridView и три кнопки для добавления, удаления и сохранения изменений. Форма в итоге будет выглядеть примерно следующим образом:

Код формы будет выглядеть следующим образом:
using System; using System.Data; using System.Windows.Forms; using System.Data.SqlClient; namespace AdoNetWinFormsApp < public partial class Form1 : Form < DataSet ds; SqlDataAdapter adapter; SqlCommandBuilder commandBuilder; string connectionString = @"Data Source=.\SQLEXPRESS;Initial Catalog=usersdb;Integrated Security=True"; string sql = "SELECT * FROM Users"; public Form1() < InitializeComponent(); dataGridView1.SelectionMode = DataGridViewSelectionMode.FullRowSelect; dataGridView1.AllowUserToAddRows = false; using (SqlConnection connection = new SqlConnection(connectionString)) < connection.Open(); adapter = new SqlDataAdapter(sql, connection); ds = new DataSet(); adapter.Fill(ds); dataGridView1.DataSource = ds.Tables[0]; // делаем недоступным столбец id для изменения dataGridView1.Columns["Id"].ReadOnly = true; >> // кнопка добавления private void addButton_Click(object sender, EventArgs e) < DataRow row = ds.Tables[0].NewRow(); // добавляем новую строку в DataTable ds.Tables[0].Rows.Add(row); >// кнопка удаления private void deleteButton_Click(object sender, EventArgs e) < // удаляем выделенные строки из dataGridView1 foreach(DataGridViewRow row in dataGridView1.SelectedRows) < dataGridView1.Rows.Remove(row); >> // кнопка сохранения private void saveButton_Click(object sender, EventArgs e) < using (SqlConnection connection = new SqlConnection(connectionString)) < connection.Open(); adapter = new SqlDataAdapter(sql, connection); commandBuilder = new SqlCommandBuilder(adapter); adapter.InsertCommand = new SqlCommand("sp_CreateUser", connection); adapter.InsertCommand.CommandType = CommandType.StoredProcedure; adapter.InsertCommand.Parameters.Add(new SqlParameter("@name", SqlDbType.NVarChar, 50, "Name")); adapter.InsertCommand.Parameters.Add(new SqlParameter("@age", SqlDbType.Int, 0, "Age")); SqlParameter parameter = adapter.InsertCommand.Parameters.Add("@Id", SqlDbType.Int, 0, "Id"); parameter.Direction = ParameterDirection.Output; adapter.Update(ds); >> > >
Здесь для добавления объекта мы будем обращаться к хранимой процедуре sp_CreateUser, которая была добавлена в базу данных в прошлой теме.
В конструкторе данные загружаются в DataSet, первая таблица которого устанавливается в качестве источника данных для dataGridView1:
dataGridView1.DataSource = ds.Tables[0];
Также в конструкторе устанавливается полное выделение строки и запрет на ручное добавление новых строк:
dataGridView1.SelectionMode = DataGridViewSelectionMode.FullRowSelect; dataGridView1.AllowUserToAddRows = false;
В обработчике кнопки добавления создается новая строка, которая добавляется в таблицу объекта DataSet. И так как мы ранее установили привязку к источнику данных, то автоматически новая строка также будет добавляться и в dataGridView1:
private void addButton_Click(object sender, EventArgs e) < DataRow row = ds.Tables[0].NewRow(); // добавляем новую строку в DataTable ds.Tables[0].Rows.Add(row); >
В обработчике кнопки удаления удаляются выделенные строки в dataGridView1. Опять же в силу привязки к источнику данных будет также происходить удаление и из таблицы в DataSet:
private void deleteButton_Click(object sender, EventArgs e) < foreach(DataGridViewRow row in dataGridView1.SelectedRows) < dataGridView1.Rows.Remove(row); >>
Для обновления на не нужна никакая кнопка, так как мы можем нажать на любую ячейку таблицы (кроме заблокированного для изменения столбца Id) и изменить в ней данные. Однако сами по себе добавление новой строки, удаление строк, изменение ячеек ни как автоматически не отразятся на базе данных. И чтобы бд синхронизировалась, пользователю надо будет нажать на кнопку сохранения, обработчик которой выглядит следующим образом:
private void saveButton_Click(object sender, EventArgs e) < using (SqlConnection connection = new SqlConnection(connectionString)) < connection.Open(); adapter = new SqlDataAdapter(sql, connection); commandBuilder = new SqlCommandBuilder(adapter); adapter.InsertCommand = new SqlCommand("sp_CreateUser", connection); adapter.InsertCommand.CommandType = CommandType.StoredProcedure; adapter.InsertCommand.Parameters.Add(new SqlParameter("@name", SqlDbType.NVarChar, 50, "Name")); adapter.InsertCommand.Parameters.Add(new SqlParameter("@age", SqlDbType.Int, 0, "Age")); SqlParameter parameter = adapter.InsertCommand.Parameters.Add("@Id", SqlDbType.Int, 0, "Id"); parameter.Direction = ParameterDirection.Output; adapter.Update(ds); >>
Как в прошлой теме здесь устанавливается у адаптера команда на добавление InsertCommand и затем вызывается метод Update() . В итоге мы можем добавить несколько строк, удалить, изменить, и потом один раз мы нажмем на кнопку, и все изменения будут применены к базе данных.
Привязка данных из базы

Рассмотрим простое окно, показанное на рисунке ниже. Оно позволяет пользователю указывать код машины, после чего отображает соответствующую информацию о машине в контейнере Grid (в нижней части окна):

Во время проектирования этого окна нет доступа к объекту CarTable, который поставит данные во время выполнения. Тем не менее, создавать привязки можно и без указания источника данных. Необходимо просто указать свойство класса CarTable, которое будет использовать каждый элемент.
Ниже приведен код разметки для отображения объекта CarTable:
Car ID: Марка: Модель: Цена (руб): Описание:
Обратите внимание, что контейнер Grid, служащий оболочкой для всех этих деталей, имеет имя, так что им можно манипулировать в коде и завершить привязку данных.
При первом запуске приложения никакая информация не отображается. Даже если определить необходимые привязки, никакого объекта источника не доступно. Когда пользователь щелкает на кнопке во время выполнения, извлекаются данные о соответствующей модели машины. Хотя каждую привязку можно создать программно, это не имеет особого смысла (и не сэкономит много кода по сравнению с заполнением элементов управления вручную).
Однако свойство DataContext предлагает блестящую альтернативу. Если установить его для контейнера Grid, содержащего все выражения привязки данных, то все выражения будут использовать его для заполнения себя данными.
Ниже приведен код обработки событий щелчка на кнопке пользователем:
private void cmdGetCar_Click(object sender, RoutedEventArgs e)
Текущий класс CarTable предполагает получение полного комплекта данных о машине. Однако таблицы базы данных часто включают поля, допускающие значения null, которые указывают на отсутствующую или неприменимую информацию. Это отражается в классах данных с помощью допускающих null типов данных для простых числовых значений или дат. Например, в сущностном классе CarTable можно использовать int? вместо int. Естественно, ссылочные типы, такие как строки и полноценные объекты, всегда поддерживают значения null.
Результат привязки значения null предсказуем — целевой элемент вообще ничего не отображает. Для числовых полей это поведение полезно, поскольку позволяет отличать отсутствующее значение (когда элемент не показывает ничего) от нулевого значения (когда показывается текст 0). Тем не менее, следует отметить, что есть возможность изменить способ отображения WPF значений null, устанавливая свойство TargetNullValue в выражении привязки. Если сделать это, то вместо null будет отображаться указанное значение. Вот пример отображения текста [Описание не предоставлено], когда свойство CarTable.Decription равно null:
Text=""
Квадратные скобки в тексте TargetNullValue не обязательны. В данном случае они служат для подсказки пользователю, что отображаемый текст не взят из базы данных.
Обновление базы данных
Для того чтобы включить обновления базы данных в этом примере, дополнительно ничего делать не понадобится. Свойство TextBox.Text использует двустороннюю привязку по умолчанию. В результате объект CarTable модифицируется в случае редактирования содержимого текстовых полей. (Формально каждое свойство обновляется при переходе на новое поле, поскольку в качестве режима обновления источника по умолчанию для свойства TextBox.Text установлен LostFocus.)
Зафиксировать изменения в базе данных можно в любой момент. Все, что для этого понадобится — добавление метода обновления в обработчик события клика кнопки Обновить. При щелчке на ней код может получить текущий объект CarTable из контекста данных и воспользоваться им для фиксации обновления. Давайте добавим эту кнопку, видоизменив часть разметки:
private void cmdUpdateCar_Click(object sender, RoutedEventArgs e) < CarTable ct = (CarTable)gridCarDetails.DataContext; // Используем LINQ to Entities для обновления базы данных AutoShopEntities context = new AutoShopEntities(); CarTable ct1 = context.CarTables .Where(p =>p.ID == ct.ID) .Single(); ct1.ModelName = ct.ModelName; ct1.ModelNumber = ct.ModelNumber; ct1.Cost = ct.Cost; ct1.Description = ct.Description; context.SaveChanges(); >
С этим примером связана одна потенциальная загвоздка. После щелчка на кнопке Обновить фокус переходит к этой кнопке и все незафиксированные изменения в текстовых полях применяются к объекту CarTable. Однако если сделать кнопку Обновить кнопкой по умолчанию (установив свойство IsDefault в true), появится другая возможность. Пользователь сможет внести изменения в одно из полей и нажать клавишу , чтобы запустить процесс обновления без фиксации последнего изменения. Во избежание такой ситуации необходимо явно передать фокус, прежде чем выполнять любой код базы данных:
FocusManager.SetFocusedElement(this, (Button)sender);
Datagrid как подключить бд
В прошлой теме была создана база данных, теперь подключимся к ней из приложения. В любом проекте WPF, как и в ряде других типов проектов для .NET, по умолчанию есть файл конфигурации, который называется app.config и который имеет следующее содержимое:
Добавим в него строку подключения к бд, изменив файл следующим образом:
Для определения всех подключений в программе в пределах узла добавляется новый узел . В этом узле определяются строки подключения с помощью элемента . Каждая строка подключения имеет название, определяемое с помощью атрибута name . В данном случае строка подключения называется «DefaultConnection». Название может быть произвольное.
Атрибут connectionString собственно хранит строку подключения. Он состоит из трех частей:
- Data Source=.\SQLEXPRESS : указывает на название сервера. По умолчанию для MS SQL Server Express используется «.\SQLEXPRESS»
- Initial Catalog=mobiledb : название базы данных. Так как база данных называется mobiledb, то соответственно здесь данное название и указываем
- Integrated Security=True : задает режим аутентификации
Так как мы будем подключаться к базе данных MS SQL Server, то соответственно мы будем использовать провайдер для SQL Server, функциональность которого заключена в пространстве имен System.Data.SqlClient.
Далее определим код графического интерфейса в xaml:
" Header="Модель" Width="120"/> " Header="Производитель" Width="125"/> " Header="Цена" Width="80"/>
Здесь определен довольно простой интерфейс: датагрид для отображения данных, и две кнопки для обновления данных в бд и для удаления. В итоге приложение будет выглядеть следующим образом:

Теперь определим код подключения и все обработчики кнопок в файле кода c#:
using System; using System.Windows; using System.Windows.Controls; using System.Data.SqlClient; using System.Data; using System.Configuration; namespace DbApp < public partial class MainWindow : Window < string connectionString; SqlDataAdapter adapter; DataTable phonesTable; public MainWindow() < InitializeComponent(); // получаем строку подключения из app.config connectionString = ConfigurationManager.ConnectionStrings["DefaultConnection"].ConnectionString; >private void Window_Loaded(object sender, RoutedEventArgs e) < string sql = "SELECT * FROM Phones"; phonesTable = new DataTable(); SqlConnection connection=null; try < connection = new SqlConnection(connectionString); SqlCommand command = new SqlCommand(sql, connection); adapter = new SqlDataAdapter(command); // установка команды на добавление для вызова хранимой процедуры adapter.InsertCommand = new SqlCommand("sp_InsertPhone", connection); adapter.InsertCommand.CommandType = CommandType.StoredProcedure; adapter.InsertCommand.Parameters.Add(new SqlParameter("@title", SqlDbType.NVarChar, 50, "Title")); adapter.InsertCommand.Parameters.Add(new SqlParameter("@company", SqlDbType.NVarChar, 50, "Company")); adapter.InsertCommand.Parameters.Add(new SqlParameter("@price", SqlDbType.Int, 0, "Price")); SqlParameter parameter = adapter.InsertCommand.Parameters.Add("@Id", SqlDbType.Int, 0, "Id"); parameter.Direction = ParameterDirection.Output; connection.Open(); adapter.Fill(phonesTable); phonesGrid.ItemsSource = phonesTable.DefaultView; >catch(Exception ex) < MessageBox.Show(ex.Message); >finally < if(connection!=null) connection.Close(); >> private void UpdateDB() < SqlCommandBuilder comandbuilder = new SqlCommandBuilder(adapter); adapter.Update(phonesTable); >private void updateButton_Click(object sender, RoutedEventArgs e) < UpdateDB(); >private void deleteButton_Click(object sender, RoutedEventArgs e) < if (phonesGrid.SelectedItems != null) < for (int i = 0; i < phonesGrid.SelectedItems.Count; i++) < DataRowView datarowView = phonesGrid.SelectedItems[i] as DataRowView; if (datarowView != null) < DataRow dataRow = (DataRow)datarowView.Row; dataRow.Delete(); >> > UpdateDB(); > > >
Вся работа с бд производится стандартными средствами ADO.NET и прежде всего классом SqlDataAdapter. Вначале мы получаем в конструкторе строку подключения, которая определена выше в файле app.config:
connectionString = ConfigurationManager.ConnectionStrings["DefaultConnection"].ConnectionString;
Чтобы задействовать эту функциональность, нам надо добавить в проект библиотеку System.Configuration.dll .
Далее в обработчике загрузки окна Window_Loaded создаем объект SqlDataAdapter:
adapter = new SqlDataAdapter(command);
В качестве команды для добавления объекта устанавливаем ссылку на хранимую процедуру:
adapter.InsertCommand = new SqlCommand("sp_InsertPhone", connection);
Получаем данные из БД и осуществляем привязку:
adapter.Fill(phonesTable); phonesGrid.ItemsSource = phonesTable.DefaultView;
За обновление отвечает метод UpdateDB() :
private void UpdateDB()
Чтобы обновить данные через SqlDataAdapter, нам нужна команда обновления, которую можно получить с помощью объекта SqlCommandBuilder. Для самого обновления вызывается метод adapter.Update() .
Причем не важно, что мы делаем в программе — добавляем, редактируем или удаляем строки. Метод adapter.Update сделает все необходимые действия. Дело в том, что при загрузке данных в объект DataTable система отслеживает состояние загруженных строк. В методе adapter.Update() состояние строк используется для генерации нужных выражений языка SQL, чтобы выполнить обновление базы данных. Более подробно про обновление с помощью адаптеров данных можно почитать здесь: Обновление БД из DataSet вручную
В обработчике кнопки обновления просто вызывается этот метод UpdateDB, а в обработчике кнопки удаления предварительно удаляются все выделенные строки.
Таким образом, мы можем вводить в DataGrid новые данные, редактировать там же уже существующие, сделать множество изменений, и после этого нажать на кнопку обновления, и все эти изменения синхронизируются с базой данных.
Причем важно отметить действие хранимой процедуры — при добавлении нового объекта данные уходят на сервер, и процедура возвращает нам id добавленной записи. Этот id играет большую роль при генерации нужного sql-выражения, если мы захотим эту запись изменить или удалить. И если бы не хранимая процедура, то нам пришлось бы после добавления данных загружать заново всю таблицу в datagrid, только чтобы у новой добавленной записи был в datagrid id. И хранимая процедура избавляет нас от этой работы.
Также здесь мы могли бы выполнять обновление данных сразу после редактирования строки. Для этого нужно задействовать событие RowEditEnding элемента DataGrid:
public MainWindow() < InitializeComponent(); connectionString = ConfigurationManager.ConnectionStrings["DefaultConnection"].ConnectionString; phonesGrid.RowEditEnding += PhonesGrid_RowEditEnding; >private void PhonesGrid_RowEditEnding(object sender, DataGridRowEditEndingEventArgs e)
И если после окончания редактирования мы нажмем на Enter, то срабатает обработчик события RowEditEnding, который обновит базу данных.
Итак, здесь рассмотрен простейший способ работы с базой данных в WPF. Далее мы рассмотрим еще один способ, который подразумевает применение технологии Entity Framework.
DataGridView — просмотр баз данных LocalDB

Приложение выполнено на каркасе Windows Forms. Для просмотра списка баз данных SQL сервера LocalDB и их содержимого используются элементы управления DataGridView. При загрузке приложения в первом DataGridView dgvDatabase выводится список баз данных. Щелкая по строкам баз данных, во втором DataGridView dgvTables отображается список таблиц соответствующей базы. Выбирая строки таблиц, в третьем DataGridView dgvContentTable раскрывается выбранная таблица с данными столбцов. Ошибки обработки входных данных отслеживаются в методе события DataError.
Приложение работает на драйвере поставщика данных пространства имен Microsoft.Data.SqlClient технологии доступа к данным ADO.NET, библиотеки добавляются в проект посредством сервиса загрузки пакетов NuGet. Результаты SQL запросов возвращаются в виде объекта DataTable. Таблицы, в свою очередь, являются источником данных для элементов управления DataGridView.
Примечание. Для SQL клиента рекомендуется использовать пространство имен Microsoft.Data.SqlClient, но не System.Data.SqlClient, так как более расширенная поддержка и новые функции (в том числе поддержка UTF-8) будут внедряться только в Microsoft.Data.SqlClient. Ссылка на информацию о SQL клиентах в статье Introducing the new Microsoft.Data.SqlClient
Элемент управления DataGridView Windows Forms
DataGridView предназначен для отображения данных в виде таблицы. Источник данных указывается для свойства DataGridView.DataSource . Источники данных могут быть различных типов. В документации в качестве источников указаны типы реализующие следующие интерфейсы:
- IList, включая одномерные массивы;
- IListSource, например классы DataTable и DataSet;
- IBindingList, например класс BindingList ;
- IBindingListView, например класс BindingSource.
В описываемом приложении источником данных служат объекты DataTable, представляющие одну таблицу в памяти.
Подключение к серверу LocalDB
Для инкапсуляции подключения и формирования запросов к серверу баз данных создан статический класс ConnectDB с одним закрытым свойством и одним открытым методом выполнения SQL запросов. Строка подключения создается объектом специализированного класса SqlConnectionStringBuilder , предназначенного для построения синтактически правильных строк подключения. Для работы со списком баз данных сервера нет необходимости определять свойство SqlConnectionStringBuilder.InitialCatalog. Для подключения к LocalDB используется режим проверки текущей учетной записи Windows.
Программный код класса формирующий подключение и запросы к серверу LocalDB:
internal class ConnectDB < // Формирование строки подключения к локальному серверу баз данных. private static string ConnectionString < get < var sb = new SqlConnectionStringBuilder < // Путь подключения к локальному серверу, // Экземпляры локальных серверов могут отличаться именами. DataSource = @"(LocalDB)MSSQLLocalDB", // Проверка подлинности Windows. IntegratedSecurity = true, Pooling = true >; return sb.ConnectionString; > > // Метод выполнения запросов к SQL серверу. public static DataTable SqlQuery(string queryString) < string connectionString = ConnectDB.ConnectionString; using SqlConnection connection = new(connectionString); using SqlCommand command = new(queryString, connection); connection.Open(); // Результаты возвращаются в виде таблицы. DataTable result = new(); using SqlDataReader reader = command.ExecuteReader(); result.Load(reader); return result; >>
Инициализация списка баз данных LocalDB
Доступ к основным параметрам баз данных SQL сервера предоставляет системное представление SYS.DATABASES в виде таблицы со множеством столбцов показателей. Для каждой базы данных отводится одна строка системной таблицы.
Инициализация списка баз данных локального SQL сервера происходит в методе Init() , который вызывается в конструкторе главной формы приложения. Для каждой базы данных запрос ограничивается несколькими параметрами: имя, идентификатор, состояние базы (ONLINE, OFFLINE и др.), уровень совместимости (версия SQL сервера), доступ пользователя (MULTI_USER, SINGLE_USER, RESTRICTED_USER) и дата создания. Для удобства параметры могут быть переименованы, при этом имена включающие пробелы должны быть заключены в квадратные скобки.
Возврат запроса в виде объекта DataTable присваивается свойству DataGridView.DataSource . В результате работы инициирующего метода поле DataGridView заполняется списком баз данных сервера LocalDB, визуализируя информацию в виде таблицы.
private void Init() < // Имя параметра состоящее из двух слов должны быть заключены в квадратные скобки, // оно будет восприниматься как неразрывное целое. string queryString = "SELECT name, database_id as Идентификатор, state_desc as Состояние, compatibility_level as [Версия SQL Server], user_access_desc as [Доступ пользователя], create_date as [Дата создания] FROM sys.databases;"; // Запрошенные данные выдаются в виде таблицы. DataTable dataTable = ConnectDB.SqlQuery(queryString); // Полученная таблица задается в качестве источника данных DataGridView. // Данные выводятся в верхний DataGridView, предназначенный для // отображения информации о базах данных SQL сервера. dgvDatabase.DataSource = dataTable; >
Вывод списка таблиц выбранной базы данных
При выделении какой-либо ячейки в первом DataGridView отображения баз данных, во втором DataGridView выводится таблица с данными всех таблиц выбранной базы данных. Информацию о таблицах базы данных можно получить различными способами, например: метаданные из системного представления INFORMATION_SCHEMA.TABLES и sys.tables. Перед запросом информации о таблицах выбранную базу указываем инструкцией «USE Database_Name» , тогда выдаются сведения о таблицах только указанной базы данных.
В качестве метода исполняющего процедуру запроса списка таблиц для следующего элемента DataGridView, в приложении используется событие получения фокуса RowEnter строкой объекта DataGridView dgvDatabase . Имя выбранной базы данных сохраняется в свойстве dgvDatabase.Tag , это свойство имеет тип object и поэтому может хранить объекты любого типа. Сохранение имени выбранной базы необходимо для отображения столбцов выбранной таблицы в последнем элементе DataGridView.
private void DgvDatabase_RowEnter(object sender, DataGridViewCellEventArgs e) < // Запоминаем выбранную базу данных. dgvDatabase.Tag = dgvDatabase.Rows[e.RowIndex].Cells["name"].Value; string queryString = "USE [" + dgvDatabase.Tag + "]; SELECT * FROM INFORMATION_SCHEMA.TABLES"; // Запрос выдающий аналогичные данные. // string queryString = "SELECT * FROM [" + dgvDatabase.Tag + "].INFORMATION_SCHEMA.TABLES"; // Дополнительная, более полная, информация о таблицах выбранной базы данных. // string queryString = "USE [" + dgvDatabase.Tag + "]; SELECT * FROM sys.tables"; DataTable dataTable = ConnectDB.SqlQuery(queryString); // Передача полученных данных следующему DataGridView dgvTables.DataSource = dataTable; >
Вывод содержимого выбранной таблицы
Следующий этап от общего к частному — отображение подробностей выбранной таблицы. Для этого в событии RowEnter DataGridView dgvTables выполняется запрос к серверу LocalDB, используя сохраненное имя текущей базы данных и индекс фокусной строки. Результат присваивается элементу DataGridView dgvContentTable в качестве источника данных.
private void DgvTables_RowEnter(object sender, DataGridViewCellEventArgs e) < // Используем сохраненное имя базы данных. // Имя таблицы получаем от столбца TABLE_NAME выбранной строки. string queryString = "USE [" + dgvDatabase.Tag + "]; SELECT * FROM " + dgvTables.Rows[e.RowIndex].Cells["TABLE_NAME"].Value; DataTable dataTable = ConnectDB.SqlQuery(queryString); // Передача данных в DataGridView отображения столбцов // выбранной строки. dgvContentTable.DataSource = dataTable; >
Отслеживание ошибок преобразования при выводе данных
У класса DataGridView есть удобное событие DataGridView.DataError, в котором можно отследить возникновение ошибки во время анализа входной информации источника данных и управлять исключением вызванным этой ошибкой. По умолчанию, пустой метод события освобождает приложение от выбрасывания исключений связанных с обработкой источника данных.
Для упрощения один метод отслеживает события ошибок во всех объектах DataGridView, параметр sender служит для определения объекта, в котором произошла ошибка. Подробная текстовая информация о возникшей ошибке и координаты ячейки выводятся в диалоговое окно. Практический пример обработки ошибок можно посмотреть на работа DataGridView в паре с DataTable.
private void dgvDatabase_DataError(object sender, DataGridViewDataErrorEventArgs e) < // --- Перехват ошибок --- DataGridView? dgv = sender as DataGridView; // Формирование текстовой информации об ошибке и // координате невалидной ячейки. string error = "Ошибка в "; // Определение объекта DataGridView в котором произошла ошибка. string select = dgv switch < _ when dgvDatabase == dgv =>"dgvDatabase!", _ when dgvTables == dgv => "dgvTables!", _ when dgvContentTable == dgv => "dgvContentTable!", _ => error = "Неизвестная ошибка!" >; string coordinateError = " " + "row=" + e.RowIndex + ";col=" + e.ColumnIndex + ";"; MessageBox.Show(error + select + coordinateError + " " + e.Exception.Message, "Внимание!", MessageBoxButtons.OK, MessageBoxIcon.Error); >
Исходник приложения
Исходник приложения для вывода информации о базах данных сервера SQL LocalDB написан в среде MS Visual Studio 2022, Windows Forms, платформа .NET 6.0.
Скачать исходник
Тема: «DataGridView — просмотр баз данных LocalDB»
WinFormsLocalDB-vs17.zip Размер: 3219 Кбайт Загрузки: 186