Основы ADO .NET
Изменение данных в DataTable и состояние строки таблицы
Основной контроль за изменениями данных в таблице возлагается на строки – объекты класса DataRow.
Для строки определены несколько состояний, которые объявлены в перечислении RowState. Контроль за сохраняемой в строках таблицы информацией обеспечивается посредством определения состояния строки, которое обеспечивается одноименным ( RowState ) свойством – членом класса DataRow.
Пример. Создание таблицы, работа с записями
using System;
using System.Data;
namespace Rolls01
{
// Работа с таблицей:
// определение структуры таблицы,
// сборка записи (строки таблицы),
// добавление новой записи в таблицу,
// индексация записей,
// выбор значения поля в строке,
// изменение записи.
public class RollsData
{
public DataTable rolls;
int rollIndex;
public RollsData()
{
rollIndex = 0;
// Создается объект "таблица".
rolls = new DataTable("Rolls");
// Задаются и подсоединяются столбики, которые определяют тип таблицы.
// Ключевой столбец.
DataColumn dc = rolls.Columns.Add("nRoll",typeof(Int32));
dc.AllowDBNull = false;
dc.Unique = true;
//rolls.PrimaryKey = dc;
// Прочие столбцы, значения которых определяют физические
// характеристики объектов.
rolls.Columns.Add("Victim",typeof(Int32));
// Значения координат.
rolls.Columns.Add("X", typeof(Single));
rolls.Columns.Add("Y", typeof(Single));
// Старые значения координат.
rolls.Columns.Add("lastX", typeof(Single));
rolls.Columns.Add("lastY", typeof(Single));
// Составляющие цвета.
rolls.Columns.Add("Alpha", typeof(Int32));
rolls.Columns.Add("Red", typeof(Int32));
rolls.Columns.Add("Green", typeof(Int32));
rolls.Columns.Add("Blue", typeof(Int32));
}
// Добавление записи в таблицу.
public void AddRow(int key,
int victim,
float x,
float y,
float lastX,
float lastY,
int alpha,
int red,
int green,
int blue)
{
// Новая строка создается от имени таблицы,
// тип которой определяется множеством ранее
// добавленных к таблице столбцов. Подобным образом
// созданная строка содержит кортеж ячеек
// соответствующего типа.
DataRow dr = rolls.NewRow();
// Заполнение ячеек строки.
dr["nRoll"] = key;
dr["Victim"] = victim;
dr["X"] = x;
dr["Y"] = y;
dr["lastX"] = lastX;
dr["lastY"] = lastY;
dr["Alpha"] = alpha;
dr["Red"] = red;
dr["Green"] = green;
dr["Blue"] = blue;
// Созданная и заполненная строка
// подсоединяется к таблице.
rolls.Rows.Add(dr);
}
// Выборка значений очередной строки таблицы.
// Ничего особенного. Для доступа к записи (строке) используются
// выражения индексации по отношению к множеству Rows.
// Для доступа к полю выбранной записи используются
// "индексаторы-идентификаторы".
public void NextRow(ref rPoint p)
{
p.index = (int)rolls.Rows[rollIndex]["nRoll"];
p.victim = (int)rolls.Rows[rollIndex]["Victim"];
p.p.X = (float)rolls.Rows[rollIndex]["X"];
p.p.Y = (float)rolls.Rows[rollIndex]["Y"];
p.lastXdirection = (float)rolls.Rows[rollIndex]["lastX"];
p.lastYdirection = (float)rolls.Rows[rollIndex]["lastY"];
p.c.alpha = (int)rolls.Rows[rollIndex]["Alpha"];
p.c.red = (int)rolls.Rows[rollIndex]["Red"];
p.c.green = (int)rolls.Rows[rollIndex]["Green"];
p.c.blue = (int)rolls.Rows[rollIndex]["Blue"];
p.cp.alpha = p.c.alpha – 50;
p.cp.red = p.c.red – 10;
p.cp.green = p.c.green – 10;
p.cp.blue = p.c.blue – 10;
rollIndex++; // Изменили значение индекса строки.
if (rollIndex == rolls.Rows.Count) rollIndex = 0;
}
// Та же выборка, но в параметрах дополнительно указан индекс записи.
public void GetRow(ref rPoint p, int key)
{
p.index = (int)rolls.Rows[key]["nRoll"];
p.victim = (int)rolls.Rows[key]["Victim"];
p.p.X = (float)rolls.Rows[key]["X"];
p.p.Y = (float)rolls.Rows[key]["Y"];
p.lastXdirection = (float)rolls.Rows[key]["lastX"];
p.lastYdirection = (float)rolls.Rows[key]["lastY"];
p.c.alpha = (int)rolls.Rows[key]["Alpha"];
p.c.red = (int)rolls.Rows[key]["Red"];
p.c.green = (int)rolls.Rows[key]["Green"];
p.c.blue = (int)rolls.Rows[key]["Blue"];
p.cp.alpha = p.c.alpha – 50;
p.cp.red = p.c.red – 10;
p.cp.green = p.c.green – 10;
p.cp.blue = p.c.blue – 10;
if (rollIndex == rolls.Rows.Count) rollIndex = 0;
}
// Изменяется значение координат и статуса точки.
// Значение порядкового номера объекта-параметра используется
// в качестве первого индексатора, имя столбца – в
// качестве второго. Скорость выполнения операции присваивания
// значения ячейке оставляет желать лучшего.
public void SetXYStInRow(rPoint p)
{
rolls.Rows[p.index]["X"] = p.p.X;
rolls.Rows[p.index]["Y"] = p.p.Y;
rolls.Rows[p.index]["lastX"] = p.lastXdirection;
rolls.Rows[p.index]["lastY"] = p.lastYdirection;
rolls.Rows[p.index]["Victim"] = p.victim;
}
public void ReSetRowIndex()
{
rollIndex = 0;
}
}
}
Листинг
18.3.
Relations
В классе DataSet определяется свойство Relations – набор объектов – представителей класса DataRelations. Каждый такой объект определяет связи между составляющими объект DataSet объектами DataTable (таблицами). Если в DataSet более одного набора DataTable, набор DataRelations будет содержать несколько объектов типа DataRelation. Каждый объект определяет связи между таблицами – DataTable. Таким образом, в объекте DataSet реализуется полный набор элементов для управления данными, включая сами таблицы, ограничения и отношения между таблицами.
Constraints
Объекты – представители класса Constraint в наборе Constraints объекта DataTable позволяет задать на множестве объектов DataTable различные ограничения. Например, можно создать объект Constraint, гарантирующий, что значение поля или нескольких полей будут уникальны в пределах DataTable.
DataView
Объекты – представители класса DataView НЕ ПРЕДНАЗНАЧЕНЫ для организации визуализации объектов DataTable.
Их назначение – простой последовательный доступ к строкам таблицы. Объекты DataView являются средством перебора записей таблицы. При обращении ЧЕРЕЗ объект DataView к таблице получают данные, которые хранятся в этой таблице.
DataView нельзя рассматривать как таблицу. DataView не может обеспечить представление таблиц. Также DataView не может обеспечить исключения и добавления столбцов. Таким образом, DataView НЕ является средством преобразования исходной информации, зафиксированной в таблице.
После создания объекта DataView и его настройки на конкретную таблицу появляется возможность перебора записей, их фильтрации, поиска и сортировки.
DataView предоставляет средства динамического представления набора данных, к которому можно применить различные вырианты сортировки и фильтрации на основе критериев, обеспечиваемых базой данных.
Класс DataView обладает большим набором свойств, методов и событий, что позволяет с помощью объекта – представителя класса DataView создавать различные представления данных, содержащихся в DataTable.
Используя этот объект, можно представлять содержащиеся в таблице данные в соответствии с тем или иным порядком сортировки, а также организовать различные варианты фильтрации данных.
DataView предоставляет динамический взгляд на содержимое таблицы в зависимости от установленного в таблице порядка представления и вносимых в таблицы изменений.
Функционально реализация DataView отличается от метода Select, определенного в DataTable, который возвращает массив DataRow (строк).
Для управления установками представления для всех таблиц, входящих в DataSet, используется объект – представитель класса DataViewManager.
DataViewManager предоставляет удобный способ управления параметрами настройки представления по умолчанию для каждой таблицы.
Примеры использования DataView
Для организации просмотра информации, сохраняемой объектом-представителем класса DataTable через объект – представитель класса DataView, этот объект необходимо связать с таблицей.
Таким образом, в приложении создается (независимый!) вьюер, который связывается с таблицей.
Итак, имеем
DataTable tbl = new DataTable("XXX"); // Объявлен и определен объект "таблица".
DataView vie; // Ссылка на вьюер.
vie = new DataView(); // Создали...
vie.Table = tbl; // Привязали таблицу к вьюеру.
// Можно и так...
vie = new DataView(tbl); // Создали и сразу привязали...Управление вьюером также осуществляется посредством различных достаточно простых манипуляций, включая изменение свойств объекта. Например, сортировка включается следующим образом:
// Предполагается наличие кнопочных переключателей, // в зависимости от состояния которых в свойстве Sort // вьюера выставляется в качестве значения имя того или // иного столбца. Результат сортировки становится виден // непосредственно после передачи информации объекту, // отвечающему за демонстрацию таблицы (rpDataGrid). if (rBN.Checked) rd.view.Sort = "nRoll"; if (rBX.Checked) rd.view.Sort = "X"; if (rBY.Checked) rd.view.Sort = "Y"; this.rpDataGrid.DataSource = rd.view;
Следующий пример кода демонстрирует возможности поиска, реализуемые объектом – представителем класса DataView. Сортировка обеспечивается вариантами методов Find и FindRows, которые способны в различной реализации воспринимать отдельные значения или массивы значений.
Поиск информации проводится по столбцам, предварительно перечисленным в свойстве Sort. При неудовлетворительном результате поиска метод Find возвращает отрицательное значение, метод FindRows – нулевое.
В случае успеха метода Sort возвращается индекс первой найденной записи. По этому индексу можно получить непосредственный доступ к записи:
// Выставили значение индекса
int findIndex = –1;
:::::
// Поиск в строке по полю "nRoll" (целочисленный столбец)
rd.view.Sort = "nRoll";
try
{
// Проверка на соответствие типа.
int.Parse(this.findTtextBox.Text);
// Сам поиск.
findIndex = rd.view.Find(this.findTtextBox.Text);
}
catch (Exception e1)
{
this.findTtextBox.Text = "Integer value expected...";
}
}
:::::
// Проверка результатов.
if (findIndex == –1)
{
this.findTtextBox.Text = "Row not found: " + this.findTtextBox.Text;
}
else
{
this.findTtextBox.Text =
"Yes :" + rd.view[findIndex]["nRoll"].ToString() +
"," + rd.view[findIndex]["X"].ToString() +
"," + rd.view[findIndex]["Y"].ToString();
}
Листинг
18.4.
Применение метода FindRows. В случае успешного завершения поиска возвращается массив записей, элементы которого могут быть выбраны посредством цикла foreach:
// Массив для получения результатов поиска
DataRowView[] rows;
:::::
// Поиск в строке по полю "nRoll" (целочисленный столбец)
rd.view.Sort = "nRoll";
try
{
// Проверка на соответствие типа.
int.Parse(this.findTtextBox.Text);
// Сам поиск. Возвращается массив rows.
rows = rd.view.FindRows(this.findTtextBox.Text);
}
catch (Exception e1)
{
this.findTtextBox.Text = "Integer value expected...";
}
}
:::::
// Проверка результатов.
if (rows.Length == 0)
{
this.findTtextBox.Text = "No rows found: " + this.findTtextBox.Text;
}
else
{
foreach (DataRowView row in rows)
{
this.findTtextBox.Text =
row["nRoll"].ToString() +
"," + row["X"].ToString() +
"," + row["Y"].ToString();
}
}
Листинг
18.5.
В примере демонстрируется взаимодействие автономной таблицы и "заточенного" под нее вьюера. Записи в таблицу можно добавлять как непосредственно, так и через вьюер. При этом необходимо совершать некоторое количество дополнительных действий. Через вьюер же организуется поиск записей.
using System;
using System.Data;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
namespace Lights01
{
public class DataViewForm : System.Windows.Forms.Form
{
private System.ComponentModel.Container components = null;
DataTable dt; // Таблица.
DataColumn c1, c2; // Столбцы таблцы.
DataRow dr; // Строка таблицы.
DataView dv; // Вьюер таблицы.
DataRowView rv; // Вьюер строки таблицы.
int currentCounter; // Счетчик текущей строки для вьюера таблицы.
private System.Windows.Forms.DataGrid dG;
private System.Windows.Forms.DataGrid dGforTable;
private System.Windows.Forms.Button buttPrev;
private System.Windows.Forms.Button buttFirst;
private System.Windows.Forms.Button buttLast;
private System.Windows.Forms.Button buttonFind;
private System.Windows.Forms.TextBox demoTextBox;
private System.Windows.Forms.TextBox findTextBox;
private System.Windows.Forms.Button buttonAdd;
private System.Windows.Forms.Button buttonAcc;
private System.Windows.Forms.GroupBox groupBox1;
private System.Windows.Forms.GroupBox groupBox2;
private System.Windows.Forms.Button buttNext;
public DataViewForm()
{
InitializeComponent();
CreateTable();
dG.DataSource = dv;
dGforTable.DataSource = dt;
currentCounter = 0;
rv = dv[currentCounter];
demoTextBox.Text = rv["Item"].ToString();
}
protected override void Dispose( bool disposing )
{
if( disposing )
{
if(components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}
#region Windows Form Designer generated code
// Required method for Designer support – do not modify
// the contents of this method with the code editor.
private void InitializeComponent()
{
this.dG = new System.Windows.Forms.DataGrid();
this.demoTextBox = new System.Windows.Forms.TextBox();
this.buttPrev = new System.Windows.Forms.Button();
this.buttNext = new System.Windows.Forms.Button();
this.buttFirst = new System.Windows.Forms.Button();
this.buttLast = new System.Windows.Forms.Button();
this.findTextBox = new System.Windows.Forms.TextBox();
this.buttonFind = new System.Windows.Forms.Button();
this.buttonAdd = new System.Windows.Forms.Button();
this.dGforTable = new System.Windows.Forms.DataGrid();
this.buttonAcc = new System.Windows.Forms.Button();
this.groupBox1 = new System.Windows.Forms.GroupBox();
this.groupBox2 = new System.Windows.Forms.GroupBox();
((System.ComponentModel.ISupportInitialize)(this.dG)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.dGforTable)).BeginInit();
this.groupBox1.SuspendLayout();
this.groupBox2.SuspendLayout();
this.SuspendLayout();
//
// dG
//
this.dG.DataMember = "";
this.dG.HeaderForeColor = System.Drawing.SystemColors.ControlText;
this.dG.Location = new System.Drawing.Point(8, 80);
this.dG.Name = "dG";
this.dG.Size = new System.Drawing.Size(280, 128);
this.dG.TabIndex = 0;
this.dG.MouseDown +=
new System.Windows.Forms.MouseEventHandler(this.dG_MouseDown);
//
// demoTextBox
//
this.demoTextBox.Location = new System.Drawing.Point(152, 48);
this.demoTextBox.Name = "demoTextBox";
this.demoTextBox.Size = new System.Drawing.Size(128, 20);
this.demoTextBox.TabIndex = 1;
this.demoTextBox.Text = "";
//
// buttPrev
//
this.buttPrev.Location = new System.Drawing.Point(189, 16);
this.buttPrev.Name = "buttPrev";
this.buttPrev.Size = new System.Drawing.Size(25, 23);
this.buttPrev.TabIndex = 2;
this.buttPrev.Text = "<–";
this.buttPrev.Click += new System.EventHandler(this.buttPrev_Click);
//
// buttNext
//
this.buttNext.Location = new System.Drawing.Point(221, 16);
this.buttNext.Name = "buttNext";
this.buttNext.Size = new System.Drawing.Size(25, 23);
this.buttNext.TabIndex = 3;
this.buttNext.Text = "–>";
this.buttNext.Click += new System.EventHandler(this.buttNext_Click);
//
// buttFirst
//
this.buttFirst.Location = new System.Drawing.Point(157, 16);
this.buttFirst.Name = "buttFirst";
this.buttFirst.Size = new System.Drawing.Size(25, 23);
this.buttFirst.TabIndex = 4;
this.buttFirst.Text = "<<";
this.buttFirst.Click += new System.EventHandler(this.buttFirst_Click);
//
// buttLast
//
this.buttLast.Location = new System.Drawing.Point(253, 16);
this.buttLast.Name = "buttLast";
this.buttLast.Size = new System.Drawing.Size(25, 23);
this.buttLast.TabIndex = 5;
this.buttLast.Text = ">>";
this.buttLast.Click += new System.EventHandler(this.buttLast_Click);
//
// findTextBox
//
this.findTextBox.Location = new System.Drawing.Point(8, 48);
this.findTextBox.Name = "findTextBox";
this.findTextBox.Size = new System.Drawing.Size(128, 20);
this.findTextBox.TabIndex = 6;
this.findTextBox.Text = "";
//
// buttonFind
//
this.buttonFind.Location = new System.Drawing.Point(88, 16);
this.buttonFind.Name = "buttonFind";
this.buttonFind.Size = new System.Drawing.Size(48, 23);
this.buttonFind.TabIndex = 7;
this.buttonFind.Text = "Find";
this.buttonFind.Click += new System.EventHandler(this.buttonFind_Click);
//
// buttonAdd
//
this.buttonAdd.Location = new System.Drawing.Point(8, 16);
this.buttonAdd.Name = "buttonAdd";
this.buttonAdd.Size = new System.Drawing.Size(40, 23);
this.buttonAdd.TabIndex = 8;
this.buttonAdd.Text = "Add";
this.buttonAdd.Click += new System.EventHandler(this.buttonAdd_Click);
//
// dGforTable
//
this.dGforTable.DataMember = "";
this.dGforTable.HeaderForeColor = System.Drawing.SystemColors.ControlText;
this.dGforTable.Location = new System.Drawing.Point(8, 24);
this.dGforTable.Name = "dGforTable";
this.dGforTable.Size = new System.Drawing.Size(272, 120);
this.dGforTable.TabIndex = 9;
//
// buttonAcc
//
this.buttonAcc.Location = new System.Drawing.Point(8, 152);
this.buttonAcc.Name = "buttonAcc";
this.buttonAcc.Size = new System.Drawing.Size(40, 23);
this.buttonAcc.TabIndex = 10;
this.buttonAcc.Text = "Acc";
this.buttonAcc.Click += new System.EventHandler(this.buttonAcc_Click);
//
// groupBox1
//
this.groupBox1.Controls.Add(this.buttonAcc);
this.groupBox1.Controls.Add(this.dGforTable);
this.groupBox1.Location = new System.Drawing.Point(6, 8);
this.groupBox1.Name = "groupBox1";
this.groupBox1.Size = new System.Drawing.Size(298, 184);
this.groupBox1.TabIndex = 11;
this.groupBox1.TabStop = false;
this.groupBox1.Text = "Таблица как она есть ";
//
// groupBox2
//
this.groupBox2.Controls.Add(this.buttPrev);
this.groupBox2.Controls.Add(this.buttonFind);
this.groupBox2.Controls.Add(this.buttFirst);
this.groupBox2.Controls.Add(this.buttLast);
this.groupBox2.Controls.Add(this.demoTextBox);
this.groupBox2.Controls.Add(this.buttNext);
this.groupBox2.Controls.Add(this.dG);
this.groupBox2.Controls.Add(this.buttonAdd);
this.groupBox2.Controls.Add(this.findTextBox);
this.groupBox2.Location = new System.Drawing.Point(8, 200);
this.groupBox2.Name = "groupBox2";
this.groupBox2.Size = new System.Drawing.Size(296, 216);
this.groupBox2.TabIndex = 12;
this.groupBox2.TabStop = false;
this.groupBox2.Text = "Вид через вьюер";
//
// DataViewForm
//
this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
this.ClientSize = new System.Drawing.Size(312, 421);
this.Controls.Add(this.groupBox2);
this.Controls.Add(this.groupBox1);
this.Name = "DataViewForm";
this.Text = "DataViewForm";
((System.ComponentModel.ISupportInitialize)(this.dG)).EndInit();
((System.ComponentModel.ISupportInitialize)(this.dGforTable)).EndInit();
this.groupBox1.ResumeLayout(false);
this.groupBox2.ResumeLayout(false);
this.ResumeLayout(false);
}
#endregion
private void CreateTable()
{
// Создается таблица.
dt = new DataTable("Items");
// Столбцы таблицы...
// Имя первого столбца – id, тип значения – System.Int32.
c1 = new DataColumn("id", Type.GetType("System.Int32"));
c1.AutoIncrement=true;
// Имя второго столбца – Item, тип значения – System.Int32.
c2 = new DataColumn("Item", Type.GetType("System.Int32"));
// К таблице добавляются объекты-столбцы...
dt.Columns.Add(c1);
dt.Columns.Add(c2);
// А вот массив столбцов (здесь он из одного элемента)
// для организации первичного ключа (множества первичных ключей).
DataColumn[] keyCol= new DataColumn[1];
// И вот, собственно, как в таблице задается множество первичных ключей.
keyCol[0]= c1;
// Свойству объекта t передается массив, содержащий столбцы, которые
// формируемая таблица t будет воспринимать как первичные ключи.
dt.PrimaryKey=keyCol;
// В таблицу добавляется 10 rows.
for(int i = 0; i <10;i++)
{
dr=dt.NewRow();
dr["Item"]= i;
dt.Rows.Add(dr);
}
// Принять изменения.
// Так производится обновление таблицы.
// Сведения о новых изменениях и добавлениях будут фиксироваться
// вплоть до нового обновления.
dt.AcceptChanges();
// Здесь мы применим специализированный конструктор, который
// задаст значения свойств Table, RowFilter, Sort, RowStateFilter
// объекта DataView в двух операторах кода...
//dv = new DataView(dt); // Вместо этого...
// Определение того, что доступно через объект - представитель DataView.
// Задавать можно в виде битовой суммы значений. И не все значения сразу!
// Сумма всех значений – противоречивое сочетание!
// А можно ли делать это по отдельности?
DataViewRowState dvrs = DataViewRowState.Added |
DataViewRowState.CurrentRows |
DataViewRowState.Deleted |
DataViewRowState.ModifiedCurrent |
//DataViewRowState.ModifiedOriginal |
//DataViewRowState.OriginalRows |
//DataViewRowState.None |
// Записи не отображаются.
DataViewRowState.Unchanged;
// Вот такое хитрое объявление...
// Таблица,
// | значение, относительно которого проводится сортировка,
// | |
// | | имя столбца, значения которого сортируются,
// | | |
// | | | составленное значение DataViewRowState.
// | | | |
dv = new DataView(dt, "", "Item", dvrs);
}
private void buttNext_Click(object sender, System.EventArgs e)
{
if (currentCounter+1 < dv.Count) currentCounter++;
rv = dv[currentCounter];
demoTextBox.Text = rv["Item"].ToString();
}
private void buttPrev_Click(object sender, System.EventArgs e)
{
if (currentCounter–1 >= 0) currentCounter––;
rv = dv[currentCounter];
demoTextBox.Text = rv["Item"].ToString();
}
private void buttFirst_Click(object sender, System.EventArgs e)
{
currentCounter = 0;
rv = dv[currentCounter];
demoTextBox.Text = rv["Item"].ToString();
}
private void buttLast_Click(object sender, System.EventArgs e)
{
currentCounter =dv.Count – 1;
rv = dv[currentCounter];
demoTextBox.Text = rv["Item"].ToString();
}
private void dG_MouseDown
(object sender, System.Windows.Forms.MouseEventArgs e)
{
currentCounter = dG.CurrentRowIndex;
rv = dv[currentCounter];
demoTextBox.Text = rv["Item"].ToString();
}
// Реализация поиска требует специального опеделения порядка
// сортировки строк, который должен задаваться в конструкторе.
private void buttonFind_Click(object sender, System.EventArgs e)
{
int findIndex = –1;
// Сначала проверяем строку на соответствие формату отыскиваемого
// значения.
// В нашем случае строка должна преобразовываться в целочисленное
// значение.
try
{
int.Parse(findTextBox.Text);
}
catch
{
findTextBox.Text = "Неправильно задан номер...";
return;
}
findIndex = dv.Find(findTextBox.Text);
if (findIndex >= 0)
{
currentCounter = findIndex;
rv = dv[currentCounter];
demoTextBox.Text = rv["Item"].ToString();
}
else
{
findTextBox.Text = "Не нашли.";
}
}
private void buttonAdd_Click(object sender, System.EventArgs e)
{
// При создании новой записи средствами вьюера таблицы,
// связанный с ним вьюер строки переходит в состояние rv.IsNew.
// При этом в действиях этих объектов есть своя логика.
// И если туда не вмешиваться, при создании очередной записи
// предыдущая запись считается принятой и включается в таблицу
// автоматически.
// Контролируя состояния вьюера строки (rv.IsEdit || rv.IsNew),
// мы можем предотвратить процесс последовательного автоматического
// обновления таблицы. Все под контролем.
if (rv.IsEdit || rv.IsNew) return;
rv = dv.AddNew();
rv["Item"] = dv.Count–1;
}
private void buttonAcc_Click(object sender, System.EventArgs e)
{
// И вот мы вмешались в процесс.
// Добавление новой записи в таблицу становится возможным лишь
// после явного завершения редактирования предыдущей записи.
// Без этого попытки создания новой записи блокируются.
// Завершить редактирование.
rv.EndEdit();
// Принять изменения.
// Так производится обновление таблицы.
// Сведения о новых изменениях и добавлениях будут фиксироваться
// вплоть до нового обновления.
dt.AcceptChanges();
}
}
}
Листинг
18.6.