Примеры использования DataView




Для организации просмотра информации, сохраняемой объектом-представителем класса DataTable через объект – представитель класса DataView, этот объект необходимо связать с таблицей.

Таким образом, в приложении создается (независимый!) вьюер, который связывается с таблицей.

Итак, имеем

DataTable tbl = new DataTable("XXX"); // Объявлен и определен объект "таблица". DataView vie; // Ссылка на вьюер. vie = new DataView(); // Создали... vie.Table = tbl; // Привязали таблицу к вьюеру. // Можно и так... vie = new DataView(tbl); // Создали и сразу привязали...

Управление вьюером также осуществляется посредством различных достаточно простых манипуляций, включая изменение свойств объекта. Например, сортировка включается следующим образом:

// Предполагается наличие кнопочных переключателей, // в зависимости от состояния которых в свойстве Sort // вьюера выставляется в качестве значения имя того или // иного столбца. Результат сортировки становится виден // непосредственно после передачи информации объекту, // отвечающему за демонстрацию таблицы (rpDataGreed). 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(); }

 

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

 

 

Учебный проект 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(); } } }

 

Компонент BindingSource выступает в качестве источника данных для некоторых или всех элементов управления в форме. В Visual Studio компонент BindingSource можно привязать к элементу управления с помощью свойства DataBindings, которое можно настроить в окне Свойства.

Можно привязать компонент BindingSource как к простым источникам данных, например к одному свойству объекта или базовой коллекции, как то ArrayList, так и к сложным источникам данных, например к таблице базы данных. Компонент BindingSource действует в качестве посредника, обеспечивающего привязку и работу служб оперативного управления. Во время разработки или выполнения можно привязать компонент BindingSource к сложному источнику данных путем присвоения его свойствам DataSource и DataMember значений базы данных и таблицы соответственно. В следующем примере описывается использование компонента BindingSource в существующей архитектуре привязки данных.

 

 

 

[ComplexBindingPropertiesAttribute("DataSource", "DataMember")]public class BindingSource: Component, IBindingListView, IBindingList, IList, ICollection, IEnumerable, ITypedList, ICancelAddNew, ISupportInitializeNotification, ISupportInitialize, ICurrencyManagerProvider

 

Свойства

 

Имя Описание
AllowEdit Возвращает значение, показывающее, можно ли редактировать элементы в базовом списке.
AllowNew Возвращает или задает значение, указывающее, может ли быть использован метод AddNew для добавления элементов в список.
AllowRemove Возвращает значение, показывающее, можно ли удалять элементы из базового списка.
CanRaiseEvents Возвращает значение, показывающее, может ли компонент вызывать событие. (Унаследовано от Component.)
Container Возвращает контейнер IContainer, содержащий компонент Component. (Унаследовано от Component.)
Count Возвращает общее количество элементов в базовом списке, отфильтрованных в соответствии со значением свойства Filter.
CurrencyManager Получает диспетчер валюты, связанный с данным BindingSource.
Current Возвращает текущий элемент в списке.
DataMember Возвращает или задает список в источнике данных, к которому привязан соединитель в настоящее время.
DataSource Возвращает или задает источник данных, который привязывается к соединитель.
DesignMode Возвращает значение, указывающее, находится ли данный компонент Component в режиме конструктора в настоящее время. (Унаследовано отComponent.)
Events Возвращает список обработчиков событий, которые прикреплены к этому объекту Component. (Унаследовано от Component.)
Filter Возвращает или задает выражение, используемое для фильтрации, отображаемых строк.
IsBindingSuspended Возвращает значение, показывающее, приостановлена ли привязка списка.
IsFixedSize Возвращает значение, указывающее, имеет ли базовый список фиксированный размер.
IsReadOnly Возвращает значение, показывающее, является ли базовый список только для чтения.
IsSorted Получает значение, указывающее, сортируются ли элементы в базовом списке.
IsSynchronized Возвращает значение, показывающее, синхронизирован ли доступ к коллекции (safe потока).
Item Возвращает или задает элемент в список по указанному индексу.
List Получает список, к которому привязан соединитель.
Position Возвращает или задает индекс текущего элемента в базовом списке.
RaiseListChangedEvents Возвращает или задает значение, определяющее, будут ли события ListChanged вызываться.
Site Получает или задает экземпляр ISite для компонента Component. (Унаследовано от Component.)
Sort Возвращает или задает имена столбцов, используемые для сортировки и порядок сортировки для просмотра строки в источнике данных.
SortDescriptions Возвращает коллекцию описаний сортировки, применяемых к источнику данных.
SortDirection Возвращает направление сортировки элементов в списке.
SortProperty Инфраструктура. Возвращает PropertyDescriptor, используемый для сортировки списка.
SupportsAdvancedSorting Возвращает значение, показывающее, поддерживает ли источник данных сортировку по нескольким столбцам.
SupportsChangeNotification Возвращает значение, показывающее, поддерживает ли источник данных уведомление об изменениях.
SupportsFiltering Возвращает значение, показывающее, поддерживает ли источник данных фильтрацию.
SupportsSearching Возвращает значение, показывающее, поддерживает ли источник данных поиск с Find метод.
SupportsSorting Возвращает значение, показывающее, поддерживает ли источник данных сортировку.
SyncRoot Получает объект, который позволяет синхронизировать доступ к базовому списку.

 

Методы

 

Имя Описание
Add Добавляет существующий элемент во внутренний список.
AddNew Добавляет новый элемент в базовый список.
ApplySort(ListSortDescriptionCollection) Сортирует источник данных, используя заданные описания сортировки.
ApplySort(PropertyDescriptor, ListSortDirection) Сортирует источник данных, используя дескриптор, и направление сортировки указанного свойства.
CancelEdit Отменяет текущую операцию редактирования.
Clear Удаляет все элементы из списка.
Contains Определяет, является ли объект элемента в списке.
CopyTo Копирует содержимое List в заданный массив, начиная с указанного значения индекса.
CreateObjRef Создает объект, который содержит всю необходимую информацию для создания прокси-сервера, используемого для взаимодействия с удаленным объектом. (Унаследовано от MarshalByRefObject.)
Dispose() Освобождает все ресурсы, используемые объектом Component. (Унаследовано от Component.)
Dispose(Boolean) Выпуски неуправляемые ресурсы, используемые BindingSource выпуски и, при необходимости, управляемые ресурсы. (ПереопределяетComponent.Dispose(Boolean).)
EndEdit Применяет ожидающие изменения к базовому источнику данных.
Equals(Object) Определяет, равен ли заданный объект текущему объекту. (Унаследовано от Object.)
Finalize Освобождает неуправляемые ресурсы и выполняет другие операции очистки, перед тем как объект Component будет удален при сборке мусора. (Унаследовано от Component.)
Find(PropertyDescriptor, Object) Выполняет поиск индекса элемента, который имеет заданный дескриптор свойства.
Find(String, Object) Возвращает индекс элемента в списке с указанным именем и значением свойства.
GetEnumerator Извлекает перечислитель List.
GetHashCode Служит хэш-функцией по умолчанию. (Унаследовано от Object.)
GetItemProperties Извлекает массив PropertyDescriptor объекты, представляющие связываемые свойства списка тип источника данных.
GetLifetimeService Извлекает объект обслуживания во время существования, который управляет политикой времени существования данного экземпляра.(Унаследовано от MarshalByRefObject.)
GetListName Получает имя списка, предоставляющего данные для привязки.
GetRelatedCurrencyManager Получает связанный диспетчер валют для указанного элемента данных.
GetService Возвращает объект, представляющий службу, обеспечиваемую компонентом Component или его контейнером Container. (Унаследовано отComponent.)
GetType Возвращает объект Type для текущего экземпляра. (Унаследовано от Object.)
IndexOf Осуществляет поиск указанного объекта и возвращает индекс первого вхождения в пределах всего списка.
InitializeLifetimeService Возвращает объект обслуживания во время существования для управления политикой времени существования данного экземпляра.(Унаследовано от MarshalByRefObject.)
Insert Вставляет элемент в список по указанному индексу.
MemberwiseClone() Создает неполную копию текущего объекта Object. (Унаследовано от Object.)
MemberwiseClone(Boolean) Создает неполную копию текущего объекта MarshalByRefObject. (Унаследовано от MarshalByRefObject.)
MoveFirst Переходит к первому элементу в списке.
MoveLast Переход к последнему элементу в списке.
MoveNext Переходит к следующему элементу в списке.
MovePrevious Переход к предыдущему элементу в списке.
OnAddingNew Вызывает AddingNew событие.
OnBindingComplete Вызывает BindingComplete событие.
OnCurrentChanged Вызывает CurrentChanged событие.
OnCurrentItemChanged Вызывает CurrentItemChanged событие.
OnDataError Вызывает DataError событие.
OnDataMemberChanged Вызывает DataMemberChanged событие.
OnDataSourceChanged Вызывает DataSourceChanged событие.
OnListChanged Вызывает ListChanged событие.
OnPositionChanged Вызывает PositionChanged событие.
Remove Удаляет указанный элемент из списка.
RemoveAt Удаляет элемент по указанному индексу.
RemoveCurrent Удаляет текущий элемент из списка.
RemoveFilter Удаляет фильтр, связанный с BindingSource.
RemoveSort Удаляет сортировку, связанная с BindingSource.
ResetAllowNew Инфраструктура. Повторно инициализируется AllowNew свойство.
ResetBindings Заставляет элемент управления, связанный BindingSource, перечитать все элементы в списке и обновить их отображаемые значения.
ResetCurrentItem Заставляет элемент управления, связанный с BindingSource, перечитать выделенный элемент и обновить его отображаемое значение.
ResetItem Вызывает элемент управления к прыгнуть BindingSource перечитать элемент по указанному индексу и обновить его отображаемое значение.
ResumeBinding Возобновляет привязку данных.
SuspendBinding Приостанавливает привязки данных для предотвращения изменения из обновить связанный источник данных.
ToString Возвращает строку String, содержащую имя компонента Component, если таковое имеется. Этот метод не следует переопределять.(Унаследовано от Component.)

 

Пример использования

private void buFirst_Click(object sender, EventArgs e)

{

bsAuto.MoveFirst();

buPrior.Enabled = false;

buFirst.Enabled = false;

buNext.Enabled = true;

buLast.Enabled = true;

}

 

private void buLast_Click(object sender, EventArgs e)

{

bsAuto.MoveLast();

buPrior.Enabled = true;

buFirst.Enabled = true;

buNext.Enabled = false;

buLast.Enabled = false;

 

}

 

private void buNext_Click(object sender, EventArgs e)

{

buPrior.Enabled = true;

buFirst.Enabled = true;

bsAuto.MoveNext();

if (bsAuto.Position == bsAuto.Count - 1)

{

buPrior.Enabled = true;

buFirst.Enabled = true;

buNext.Enabled = false;

buLast.Enabled = false;

}

}

 

private void buPrior_Click(object sender, EventArgs e)

{

buNext.Enabled = true;

buLast.Enabled = true;

bsAuto.MovePrevious();

if (bsAuto.Position == 0)

{

buPrior.Enabled = false;

buFirst.Enabled = false;

buNext.Enabled = true;

buLast.Enabled = true;

}

}

 

private void buDelete_Click(object sender, EventArgs e)

{

if (MessageBox.Show("", "", MessageBoxButtons.OKCancel) == System.Windows.Forms.DialogResult.Cancel) { return; }

bsAuto.RemoveCurrent();

bsAuto_PositionChanged(this, null);

bsAuto.EndEdit();

WorkWithBase.GetDataAdapter().Update((DataTable)bsAuto.DataSource);

//WorkWithBase.myDataAdapter.Update((DataTable)bsAuto.DataSource);

}

 

private void bsAuto_PositionChanged(object sender, EventArgs e)

{

if (dataGridView1.DataSource == null) { return; }

if (bsAuto.Position > bsAuto.Count - 1) { return; }

if (bsAuto.Position == -1) { return; }

 

using (MemoryStream memoryStream = new MemoryStream())

{

//if (dataGridView1.CurrentRow.Cells["SizeOfShot"].Value == DBNull.Value) { pbShotOfNumber.Image = null; return; }

DataRowView dr = (DataRowView)bsAuto.Current;

if (dr["SizeOfShot"] == DBNull.Value) { pbShotOfNumber.Image = null; return; }

//memoryStream.Write((byte[])dataGridView1.CurrentRow.Cells["ShotOfNumber"].Value, 0, (int)dataGridView1.CurrentRow.Cells["SizeOfShot"].Value);

memoryStream.Write((byte[])dr["ShotOfNumber"], 0, (int)dr["SizeOfShot"]);

pbShotOfNumber.Image = new Bitmap(memoryStream);

}

}

...

 

 

Ход работы

  1. Для выполнения данной работы необходимо использовать проект приложения БД, разработанный в ходе выполнения предыдущей лабораторной работы.
  2. В наборе таблиц, разработанных и реализованных вами ранее, выбрать одну таблицу, наиболее пригодную, с вашей точки зрения, для демонстрации результатов решения типичных задач приложения БД.
  3. Создать объект класса DataView на основе выбранной вами таблицы, и с его помощью выполнить следующие действия: сортировку записей, фильтрацию записей, поиск записей по указанному значению одного (нескольких) полей. Отобразить результаты выполненных действий с использованием компонента DataGridView.
  4. Добавить на форму кнопки и в обработчиках событий для этих кнопок обеспечить с использованием методов компонента BindingSource навигацию, добавление и удаление записей (см. теоретические сведения и пример использования по компоненту в методических указаниях к данной лабораторной работе).

Лабораторная работа 10

Настройка табличных форм для отображения и редактирования данных из БД под пользовательские требования на примере компонента DataGridView Теоретические сведения

Рассмотрим элементный фундамент, на котором основывается функциональная мощь DataGridView. В своей простейшей форме DataGridView имеет базисные компоненты, представленные на рисунке 1.


Рисунок 1.

Помимо базисных элементов и базисного внешнего вида у этого control-а есть базовое поведение. Иными словами, если поместить новый DataGridView на форму и не производить никаких спецнастроек, то control будет:

  • Автоматически показывать заголовки колонок и заголовки строк. И те, и другие остаются видимыми при любом скроллинге.
  • Ставить на одном из заголовков строк маркер (черный треугольничек) текущей строки.
  • Выбирать целую строку, если пользователь щелкнет по заголовку строки.
  • Выбирать сразу несколько строк, если щелчок по заголовку строки производится с зажатым Ctrl или Shift. При этом текущая строка (помеченная треугольничком) всегда будет единственной.
  • Удалять все выбранные строки по нажатию на Delete.
  • Отображать ячейку, имеющую фокус ввода, особым образом.
  • Если пользователь выполнит двойной щелчок по разделителю колонок, будет произведена автоподборка ширины левой колонки.
  • Если в методе Main приложения был вызван метод EnableVisualStyles, будет применяться стиль Windows XP, выбранный в настройках рабочего стола.

Помимо этого control будет поддерживать редактирование содержимого:

  • Если пользователь выполнит двойной щелчок по ячейке (или нажмет на ней F2), данная ячейка будет переведена в режим редактирования.
  • Если пользователь изменит хотя бы один символ в редактируемой ячейке, на заголовке соответствующей строки появится спецсимвол (пишущий карандашик), и будет отображаться до тех пор, пока фокус ввода не покинет редактируемую ячейку, или пока пользователь не нажмет Esc. Последнее действие восстановит то значение ячейки, которое она содержала до входа в режим редактирования.
  • Если пользователь прокрутит control вниз до последней строчки, будет отображена дополнительная, специальная строчка для внесения новой записи. Такая строчка всегда помечена символом звездочки на заголовке. Когда пользователь любым способом перемещается в эту строку, DataGridView добавляет новую запись со значениями по умолчанию. Если фокус ввода находится в этой строке, и пользователь нажимает Esc, новая запись пропадает, а фокус ввода перемещается на строчку выше.

Если DataGridView привязан через свойство DataSource к источнику данных, то по умолчанию выполняется следующее.

  • Каждая колонка, получаемая из источника данных, вызовет добавление соответствующей колонки в control-е.
  • Названия колонок источника отобразятся в заголовках колонок.
  • Если пользователь щелкнет по заголовку колонки, строки будут автоматически отсортированы.

Излишне говорить, что практически все из перечисленного выше может быть разрешено/запрещено/настроено.

Привязка данных

Как известно, прежде чем начать усиленно и красиво отображать данные, эти самые данные надо получить. DataGridView поддерживает три режима работы с данными:

  1. Первый, основной – отображение данных из внешних коллекций (например, ListView, DataTable).
  2. Специальный режим отображения свободных (unbound) данных, то есть данные хранятся в самом control-е.
  3. Еще один особый режим работы – виртуальный (Virtual mode). В нем control посылает событие, при поступлении которого прикладной код возвращает некоторые данные. Так как данные при этом не обязаны где-то храниться, виртуальный режим может оперировать миллионами строк без каких-либо проблем с производительностью или нехваткой памяти.

80% времени control будет работать в основном режиме, так как в большинстве случаев данные будут поступать из СУБД, при этом копируясь в промежуточные коллекции, например, DataTable.

Привязывать элементы пользовательского интерфейса можно отнюдь не исключительно к таблично представленным данным. Практически любая структура данных может выступить в роли их источника – обычные объекты, массивы, коллекции и т.д. Хотя вопрос привязки данных в мире WinForms (Windows Forms Data Binding) совершенно выходит за рамки данной статьи ввиду его масштабности, не упомянуть ключевые моменты этой технологии было бы несомненным упущением. Сжато исследуем вопрос – как рекомендуется привязывать DataGridView к данным, и чем Framework 2.0 может нас порадовать при сравнении с версиями 1.x.

В Framework 2.0 процедура привязки данных упростилась. Чтобы продемонстрировать это, разберем, как осуществлялась привязка данных во Framework 1.x (см рисунок 2).


Рисунок 2.

А что сегодня? Сегодня у нас новый герой – BindingSource (см. рисунок 3).


Рисунок 3.

Приведенные выше иллюстрации показывают, что BindingSource представляет собой промежуточный слой между источником данных и control-ом, к нему привязанным. Поэтому в мире Framework 2.0 вполне возможны подобные привязки:

public partial class Form1: Form{ public Form1() { InitializeComponent(); //_biSour - объект типа BindingSource _biSour.DataSource = new PersonCollection(); //_grid - обычный, без настроек, DataGridView _grid.DataSource = _biSour; }} public class PersonCollection: System.Collections.IEnumerable{ public System.Collections.IEnumerator GetEnumerator() { for(uint i = 0; i <= 5; i++) { yield return new Person("Name_" + i.ToString(), 20 + i, 'M'); } }} public class Person{ private string _name; private uint _age; private char _gender;....// свойства, инкапсулирующие эти три поля public Person(string name, uint age, char gender) {... }}

Отображает grid с шестью записями.

Общий подход при привязке любого WinForms-control к BindingSource следующий. Допустим, у нас есть DataSet NorthwindDataSet с единственной таблицей Products. Тогда первым шагом будет привязка BindingSource к этому источнику данных:

// _biSour - объект типа BindingSource_biSour.DataSource = this.NorthwindDataSet;// сразу привязываемся к конкретной таблице_biSour.DataMember = "Products";

Теперь BindingSource сам становится полноценным источником данных. Единственное, что отличает его от "нормального" источника вроде того же DataTable, – отсутствие "собственных" данных, т.к. данные BindingSource – это данные нижележащего источника данных. Таким образом, при необходимости привязки свойства Text к колонке ProductName таблицы Products мы можем смело писать:

this.label1.DataBindings.Add(new Binding("Text", _biSour, "ProductName", true));

Так же обстоит дело со сложной привязкой той же колонки к control-у, поддерживающему подобную привязку:

this.comboBox1.DataSource = _biSour;this.comboBox1.DisplayMember = "ProductName";

Привязка DataGridView ко всей таблице Products:

//_grid - обычный, без настроек, DataGridView_grid.DataSource = _biSour;

Обратите внимание, что свойство DataMember в последнем случае остается незадействованным. BindingSource уже привязан к интересующей нас таблице, и уточнять путь к ней внутри DataSet-а необходимости нет.

Отметим, что формальное требование к источнику данных у нового control-а осталось практически неизменным по сравнению с его предшественником, DataGrid. Единственное исключение выражается в требовании того, что свойства DataSource и DataMember теперь должны в сочетании определять некоторый список, то есть коллекцию, реализующую IEnumerable или интерфейсы, унаследованные от него, также возможно использовать в качестве источника данных компонент, реализующий IListSourse. Два свойства нужны, например, для того, чтобы указать некоторый DataTable, входящий в состав DataSet.

На рисунке 4 приведена блок-схема привязки.


Рисунок 4.

С практической точки зрения все это означает, что DataGridView следует привязывать исключительно к BindingSource, который сам реализует один из требуемых интерфейсов (именно – IBindingListView) и позволяет привязываться к широкому диапазону источников данных. Вариант с источником, реализующим IEnumerable был рассмотрен выше. Если в процессе исполнения приложения нужно отслеживать изменения значений свойств DataSource и DataMember, можно воспользоваться событиями DataSourceChanged и DataMemberChanged.

Рассмотрим также событие DataGridView. DataBindingComplete. Оно будет сгенерировано как при изменении значения любого из двух упомянутых свойств, так и при наполнении control-а новыми данными (например, методом Fill адаптера данных). Нужно помнить только, что это все – события DataGridView, к самому источнику данных они никакого отношения не имеют. На практике же, чаще всего, интересны изменения данных именно в источнике, а не в control-е, эти данные отображающем. Для такого сценария пригодится объект BindingSource с его замечательными событиями AddingNew, BindingComplete, CurrentChanged, CurrentItemChanged, ListChanged и целым рядом других.

Общая архитектура

Одной из особенностей DataGridView является обилие у него классов-компаньонов. Таким образом, изучаемый control имеет расширяемую архитектуру, где значительную часть функциональности, доступной конечному пользователю, обеспечивают сторонние классы-компаньоны (или классы-плагины, если хотите). При таком подходе к вопросу, создавая свои собственные классы-плагины (или наследуя их от существующих и расширяя готовую функциональность), мы можем наращивать и видоизменять интересные нам аспекты поведения или внешнего вида конечного control-а практически до бесконечности. На рисунке 3 приведен фрагмент дерева классов.


Рисунок 5.

Какие выводы можно сделать, просматривая эту диаграмму? Классы-плагины именуются строго по шаблону DataGridView< Назначение_Плагина >.

Базовым классом для всех плагинов DataGridView является класс DataGridViewElement. Любой элемент-плагин должен уметь сообщить, к какому DataGridView он "приписан", а также уметь сообщить, в каком состоянии он находится. В данном случае "состояние" – это комбинация потенциально возможных режимов отображения элемента. К примеру, элемент может сказать, что он доступен только для чтения (ReadOnly), и что он «заморожен» (Frozen, скроллинг запрещен). Так вот, первое из двух "умений" обеспечивается свойством DataGridView (тип DataGridView) базового класса, а второе – его же свойством State, возвращающим комбинацию значений перечисления DataGridViewElementStates. Оба свойства, разумеется, доступны только для чтения.

Классы-плагины подразделяются на две фундаментальные разновидности: ячейки (cells) и полоски (bands). Если с первыми все более-менее понятно, то что есть полоски? Собственно, это не более чем линейная коллекция ячеек. Основная идея такой коллекции заключается в том, что управлять группой ячеек много проще, чем каждой одиночной ячейкой. Базовых разновидностей полосок всего две (как и можно было предположить) – строки и колонки. Итак, полоски собирают ячейки в группы и управляют ими как единой сущностью. Базовым классом для создания новых полосок служит класс DataGridViewBand. Ячейки же наследуются от абстрактного класса DataGridViewCell. Кстати, отметьте для себя интересный момент, заголовки строк и колонок тоже являются ячейками, ибо наследуются от того же абстрактного класса. Что же, идея расширения чуть ли не моментально нашла совершенно осязаемое применение. Создали, фактически, обычные ячейки, наделили их особой функциональностью – и совершенно особый визуальный элемент получает путевку в жизнь. Стоит упомянуть, что хотя заголовки колонок образуют красивую горизонтальную полоску, а строк – не менее красивую вертикальную, и, казалось бы, ничто не может помешать нам записать тех и других в члены полосок (bands), тем не менее, сделав так, мы поступим неосмотрительно. DataGridViewHeaderCell и его наследники не считаются членами полосок. И это совершенно логично. Возьмем, к примеру, полоску-колонку. Каждая обычная ячейка такой полоски (не являющаяся заголовком), по сути, совершенно идентична своим собратьям, как по внешнему виду, так и по поведению. Заголовок же будет разительно отличаться по обоим параметрам. Ровно то же самое относится к строкам. Таким образом, наследники DataGridViewHeaderCell, будучи неразрывно связанными с соответствующими полосками, членами последних все же не являются. Обычные же ячейки, безусловно, являются членами полосок. DataGridViewCell не является наследником System.Windows.Forms.Control. Зато он может содержать control-ы. Обратите внимание, что если ячейка может редактироваться (как, например, ячейка с текстом), то почти всегда функциональность редактирования обеспечивает не



Поделиться:




Поиск по сайту

©2015-2024 poisk-ru.ru
Все права принадлежать их авторам. Данный сайт не претендует на авторства, а предоставляет бесплатное использование.
Дата создания страницы: 2018-09-16 Нарушение авторских прав и Нарушение персональных данных


Поиск по сайту: