Введение в программирование на C# 2.0

Добавляем RowChanging event handler для


using System; using System.Data;
namespace DataRowsApplication00 { class DataTester { DataTable custTable;
public void DTBuild() { custTable = new DataTable("Customers"); // Добавляем столбики. custTable.Columns.Add("id", typeof(int)); custTable.Columns.Add("name", typeof(string));
// Определяем первичный ключ. custTable.Columns["id"].Unique = true; custTable.PrimaryKey = new DataColumn[] { custTable.Columns["id"] };
// Добавляем RowChanging event handler для нашей таблицы. custTable.RowChanging += new DataRowChangeEventHandler(Row_Changing); // Добавляем a RowChanged event handler для нашей таблицы. custTable.RowChanged += new DataRowChangeEventHandler(Row_Changed); }
public void RowsAdd(int id) { int x; // Добавляем строки. for (x = 0; x < id; x++) { custTable.Rows.Add(new object[] { x, string.Format("customer{0}", x) }); } // Фиксируются все изменения, которые были произведены над таблицей // со времени последнего вызова AcceptChanges. custTable.AcceptChanges(); }
public void RowsChange() { // Изменяем значение поля name во всех строках. // Все имена убираются, а на их место // подставляется буквосочетание, состоящее из // префикса vip и старого значения строки каждого клиента. // Была строка customer5 – стала vip customer5.
foreach (DataRow row in custTable.Rows) { row["name"] = string.Format("vip {0}", row["id"]); }
}
// И после вмешательства результаты становятся известны // обработчику события Row_Changing. А толку-то... private static void Row_Changing(object sender, DataRowChangeEventArgs e) { Console.WriteLine("Row_Changing Event: name={0}; action={1}", e.Row["name"], e.Action); }
// Аналогично устроен обработчик Row_Changed. private static void Row_Changed(object sender, DataRowChangeEventArgs e) { Console.WriteLine("Row_Changed Event: name={0}; action={1}", e.Row["name"], e.Action); } } class Program { static void Main(string[] args) { DataTester dt = new DataTester(); dt.DTBuild(); dt.RowsAdd(10); dt.RowsChange(); } } }
Листинг 18.1.



using System; using System.Data;
namespace DataColumnsApplication00 { class DataTester { DataTable custTable;
public void DTBuild() { custTable = new DataTable("Customers"); // Добавляем столбики. custTable.Columns.Add("id", typeof(int)); custTable.Columns.Add("name", typeof(string));
// Определяем первичный ключ. custTable.Columns["id"].Unique = true; custTable.PrimaryKey = new DataColumn[] { custTable.Columns["id"] };
// Добавление события ColumnChanging handler для таблицы. custTable.ColumnChanging += new DataColumnChangeEventHandler(Column_Changing); // Добавление события ColumnChanged event handler для таблицы. custTable.ColumnChanged += new DataColumnChangeEventHandler(Column_Changed); }
public void RowsAdd(int id) { int x; // Добавляем строки. for (x = 0; x < id; x++) { custTable.Rows.Add(new object[] { x, string.Format("customer{0}", x) }); } // Фиксируются все изменения, которые были произведены над таблицей // со времени последнего вызова AcceptChanges. custTable.AcceptChanges(); }
public void RowsChange() { // Изменяем значение поля name во всех строках. foreach (DataRow row in custTable.Rows) { row["name"] = string.Format("vip{0}", row["id"]); } }
// И после вмешательства результаты становятся известны // обработчику события Column_Changing. А толку-то... private static void Column_Changing (object sender, DataColumnChangeEventArgs e) { Console.WriteLine ("Column_Changing Event: name={0}; Column={1}; proposed name={2}", e.Row["name"], e.Column.ColumnName, e.ProposedValue); }
// Аналогично устроен обработчик Column_Changed. private static void Column_Changed (object sender, DataColumnChangeEventArgs e) { Console.WriteLine ("Column_Changed Event: name={0}; Column={1}; proposed name={2}", e.Row["name"], e.Column.ColumnName, e.ProposedValue); } } class Program { static void Main(string[] args) { DataTester dt = new DataTester(); dt.DTBuild(); dt.RowsAdd(10); dt.RowsChange(); } } }
Листинг 18.2.

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.

// Выставили значение индекса 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.

// Массив для получения результатов поиска 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.

DataSet myDataSet = new DataSet(); // Пустой объект - представитель класса DataSet. DataTable myTable = new DataTable(); // Пустая таблица создана. myDataSet.Tables.Add(myTable); // И подсоединена к объекту класса DataSet. // Определение структуры таблицы. Это мероприятие можно было // провести и до присоединения таблицы. DataColumn shipColumn = new DataColumn("Ships"); myDataSet.Tables[0].Columns.Add(shipColumn);
// Прочие столбцы подсоединяются аналогичным образом. // Таким образом формируются поля данных таблицы. // Внимание! После того как определена структура таблицы, // то есть определены ВСЕ СТОЛБЦЫ таблицы, от имени этой конкретной // таблицы порождается объект-строка. Этот объект сразу располагается // непосредственно в таблице. Для каждой определенной таблицы // метод NewRow() порождает строку // (последовательность значений соответствующего типа). // Для непосредственного // редактирования вновь созданной строки запоминается ее ссылка. // Работать со строкой через эту ссылку проще, чем с массивом // строк таблицы. DataRow myRow = myDataSet.Tables[0].NewRow();
// ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
// Остается заполнить строку таблицы содержательной информацией. // При этом может быть использован любой источник данных. // В данном примере предполагается наличие объекта типа ArrayList // с именем ShipCollection. for (int i = 0; i < ShipCollection.Count; i++) { myRow.Item[Counter] = ShipCollection[i]; }
// :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: // Заполненный объект - представитель класса DataRow добавляется // к набору Rowsкласса DataTable. myDataSet.Tables[0].Rows.Add(myRow);
Листинг 18.7.

using System; using System.Data;
namespace mergeTest { class Class1 { static void Main(string[] args) { // Создается объект DataSet. DataSet ds = new DataSet("myDataSet");
// Создается таблица. DataTable t = new DataTable("Items");
// Столбцы таблицы – это особые объекты. // Имя первого столбца – id, тип значения – System.Int32. DataColumn c1 = new DataColumn("id", Type.GetType("System.Int32")); c1.AutoIncrement=true; // Имя второго столбца – Item, тип значения – System.Int32. DataColumn c2 = new DataColumn("Item", Type.GetType("System.Int32"));
// Сборка объекта DataSet: // Добавляются объекты-столбцы... t.Columns.Add(c1); t.Columns.Add(c2);
// А вот массив столбцов (здесь он из одного элемента) // для организации первичного ключа (множества первичных ключей). DataColumn[] keyCol= new DataColumn[1];
// И вот, собственно, как в таблице задается множество первичных ключей. keyCol[0]= c1; // Свойству объекта t передается массив, содержащий столбцы, которые // формируемая таблица t будет воспринимать как первичные ключи. t.PrimaryKey=keyCol; // А что с этими ключами будет t делать? А это нас в данный момент // не касается. Очевидно, что методы, которые обеспечивают контроль // над информацией в соответствии со значениями ключей, уже где-то // "зашиты" в классе DataTable. Как и когда они будут выполняться – // не наше дело. Наше дело – указать на столбцы, которые для данной // таблицы будут ключевыми. Что мы и сделали.
// Таблица подсоединяется к объекту ds – представителю класса DataSet. ds.Tables.Add(t);
DataRow r;
// В таблицу, которая уже присоединена к // объекту ds DataSet, добавляется 10 rows. for(int i = 0; i <10;i++) { r=t.NewRow(); r["Item"]= i; t.Rows.Add(r); }
// Принять изменения. // Так производится обновление DataSet'а. // Сведения о новых изменениях и добавлениях будут фиксироваться // вплоть до нового обновления. ds.AcceptChanges(); PrintValues(ds, "Original values");
// Изменение значения в первых двух строках. t.Rows[0]["Item"]= 50; t.Rows[1]["Item"]= 111; t.Rows[2]["Item"]= 111;
// Добавление еще одной строки. // Судя по всему, значение первого столбца устанавливается автоматически. // Это ключевое поле со значением порядкового номера строки. r=t.NewRow(); r["Item"]=74; t.Rows.Add(r);
// Объявляем ссылку для создания временного DataSet. DataSet xSet;
// ДЕКЛАРАЦИЯ О НАМЕРЕНИЯХ КОНТРОЛЯ ЗА КОРРЕКТНОСТЬЮ ЗНАЧЕНИЙ СТРОКИ. // Вот так добавляется свойство, содержащее строку для описания // ошибки в значении. Наш DataSet содержит одну строку с описанием. // Это всего лишь указание на то обстоятельство, что МЫ САМИ // обязались осуществлять // некоторую деятельность по проверке чего-либо. Чтобы не забыть, // в чем проблема, // описание возможной ошибки (в свободной форме!) добавляем // в свойства строки, // значения которой требуют проверки. t.Rows[0].RowError= "over 100 (ЙЦУКЕН!)"; t.Rows[1].RowError= "over 100 (Stupid ERROR!)"; t.Rows[2].RowError= "over 100 (Ну и дела!)"; // Но одно дело – декларировать намерения, а другое – осуществлять // контроль. // Проблема проверки корректности значения – наша личная проблема. // Однако о наших намерениях контроля за значениями становится // известно объекту – представителю DataSet!
PrintValues(ds, "Modified and New Values");
// Мы вроде бы согласились проводить контроль значений. // Даже декларировали некий принцип проверки. // Однако ничего само собой не происходит. // Так вот, // // ЕСЛИ В ТАБЛИЦУ БЫЛИ ДОБАВЛЕНЫ СТРОКИ ИЛИ ИЗМЕНЕНЫ ЗНАЧЕНИЯ СТРОК // И // МЫ ОБЯЗАЛИСЬ КОНТРОЛИРОВАТЬ ЗНАЧЕНИЯ СТРОК В ТАБЛИЦЕ, // // то самое время организовать эту проверку... // Критерий правильности значений, естественно, наш! // Алгоритмы проверки – тоже НАШИ! // Единственное, чем нам может помочь ADO .NET, – это выделить // подмножество строк таблицы, // которые были добавлены или модифицированы со времени последнего // обновления нашего объекта - представителя DataSet'а,
if(ds.HasChanges(DataRowState.Modified | DataRowState.Added)& ds.HasErrors) { // И для этого мы воспользуемся методом, который позволяет обеспечить // выделение подмножества добавленных и // модифицированных строк в новый объект DataSet'а. // Use GetChanges to extract subset. xSet = ds.GetChanges(DataRowState.Modified|DataRowState.Added); PrintValues(xSet, "Subset values"); // Insert code to reconcile errors. In this case, we'll reject changes. // Вот, собственно, код проверки. Все делается своими руками. foreach(DataTable xTable in xSet.Tables) { if (xTable.HasErrors) { foreach(DataRow xRow in xTable.Rows) { // Выделенное подмножество проверяем на наличие // ошибочного значения (для нас все, что больше 100, – // уже ошибка!) Console.Write(xRow["Item"] + " "); if((int)xRow["Item",DataRowVersion.Current ]> 100) { // Находим ошибку в строке, сообщаем о ней, Console.WriteLine("Error! – " + xRow.RowError); // Возвращаем старое значение... xRow.RejectChanges(); // Отменяем значение свойства - уведомителя о возможных // ошибках для данной строки... xRow.ClearErrors(); } else Console.WriteLine("OK."); } } }
PrintValues(xSet, "Reconciled subset values");
// Сливаем измененные и откорректированные строки в основной // объект – DataSet // Merge changes back to first DataSet. ds.Merge(xSet);
PrintValues(ds, "Merged Values"); } }
// А это всего лишь вывод содержимого DataSet'а. private static void PrintValues(DataSet ds, string label) { Console.WriteLine("\n" + label); foreach(DataTable t in ds.Tables) { Console.WriteLine("TableName: " + t.TableName); foreach(DataRow r in t.Rows) { foreach(DataColumn c in t.Columns) { Console.Write("\t " + r[c] ); } Console.WriteLine(); } } } } }
Листинг 18.8.

// Объявили и определили объект соединения. private System.Data.OleDb.OleDbConnection oleDbConnection1; this.oleDbConnection1 = new System.Data.OleDb.OleDbConnection();
::::::::::
// Настроили объект соединения. // Для наглядности необходимая для установления соединения // информация представлена серией строк. oleDbConnection1.ConnectionString = @"Jet OLEDB:Global Partial Bulk Ops=2;" + @"Jet OLEDB:Registry Path=;" + @"Jet OLEDB:Database Locking Mode=1;" + @"Data Source=""F:\Users\Work\CS\DB.BD\DBTests\Lights.mdb"";" + @"Jet OLEDB:Engine Type=5;" + @"Jet OLEDB:Global Bulk Transactions=1;" + @"Provider=""Microsoft.Jet.OLEDB.4.0"";" + // Поставщик @"Jet OLEDB:System database=;" + @"Jet OLEDB:SFP=False;" + @"persist security info=False;" + @"Extended Properties=;" + @"Mode=Share Deny None;" + @"Jet OLEDB:Create System Database=False;" + @"Jet OLEDB:Don't Copy Locale on Compact=False;" + @"Jet OLEDB:Compact Without Replica Repair=False;" + @"User ID=Admin;" + @"Jet OLEDB:Encrypt Database=False";
Листинг 18.9.

private void readButton_Click(object sender, System.EventArgs e) { int i = 0; this.timer.Stop(); rd.rolls.Clear(); nPoints = 0; string strSQL = "SELECT nRolls,Victim,X,Y,oldX,OldY,Alpha,Red,Green,Blue From RollsTable"; oleDbConnection.Open(); OleDbCommand cmd = new OleDbCommand(strSQL,oleDbConnection); OleDbDataReader rdr = cmd.ExecuteReader(); while (rdr.Read()) { rd.AddRow( int.Parse((rdr["nRolls"]).ToString()), int.Parse((rdr["Victim"]).ToString()), float.Parse((rdr["X"]).ToString()), float.Parse((rdr["Y"]).ToString()), float.Parse((rdr["oldX"]).ToString()), float.Parse((rdr["oldY"]).ToString()), int.Parse((rdr["Alpha"]).ToString()), int.Parse((rdr["Red"]).ToString()), int.Parse((rdr["Green"]).ToString()), int.Parse((rdr["Blue"]).ToString()) ); i++; } rdr.Close(); oleDbConnection.Close(); rpDataGrid.DataSource = rd.rolls; nPoints = i; this.timer.Start(); }
Листинг 18.10.
Содержание раздела