4. Привязка объектов контроля к источникам данных

Слияние данных из нескольких наборов данных

вашим первым побуждением возможно было

Класс DataSet Поддерживает пару способов перемещения данных между различными наборами данных. Вашим первым побуждением, возможно, было бы просто получить ссылку DataRow Из одного набора данных, возможно, от операции Select Или при итерации таблицы, а затем добавить ее к таблице в другом наборе данных. К сожалению, такое не допускается, и будет выброшено исключение, когда строка данных добавляется к таблице, она становится частью этой таблицы и не может принадлежать одновременно более чем одной таблице. Только строка, которая была создана методом DataTable .NewRow, Может быть добавлена к этой таблице методом Add Коллекции Row Таблицы. Так как же переместить строку или набор строк, принадлежащих одному набору данных, в другой набор данных? Одним способом является использование метода Merge. Поведение этого метода может стать довольно сложным, поскольку он имеет ряд перегрузок, и оно зависит от того, в каком состоянии Находятся строки в наборе данных, откуда они поступают, и имеются ли соответствующие им строки в наборе данных, куда они вливаются. Для простых случаев, однако, все оказывается довольно прямолинейным. Рассмотрим ситуацию, когда у вас есть таблица Customers в одном наборе данных и таблица Orders в другом. Вы хотите, чтобы обе таблицы оказались в одном наборе данных, чтобы вы могли создать родительско-дочер — нее отношение между ними, определяемое внешним ключом CustomerlD, Существующим в таблице Orders. Для этого вы просто вызываете Merge На наборе данных, содержащем таблицу Customers, передав набор данных Orders. Метод Merge Создаст таблицу Orders в наборе данных Customers и скопирует в нее все строки из набора данных Orders. Вы можете затем конструировать отношение между двумя таблицами, как показано ниже: Если вы хотите добавить строку из таблицы в одном наборе данных в ту же самую таблицу в другом наборе данных с состоянием строки Added, Вы можете передать свойство ItemArray Строки-источника перегрузке метода Add Коллекции Rows Таблицы-приемника. Это перенесет значения ячеек как массив объектов в целевую таблицу, создав в ней новую строку, в которой они будут содержаться. Если вы хотите добавить строку из исходной таблицы в целевую и сохранить ее состояние, вы можете использовать метод ImportRow Класса DataTable. Следующий код показывает оба этих подхода:

Определение специального типа столбца

если бы вы собирались использовать

Итак, у нас есть специальный класс ячейки, который можно использовать в сетке, но желательно еще иметь специальный класс столбца, который содержал бы ячейки StatusCell И мог использоваться для организации сетки и привязки данных. Если бы вы собирались использовать специальный тип ячейки исключительно программным способом, можно было бы просто конструировать экземпляр базового класса DataGridViewColumn, Передав конструктору класса экземпляр StatusCell, Который будет уста-новлен в качестве шаблона CellTempiate Для столбца. Однако такой подход не позволит использовать для спецификации привязанного или несвязанного столбца ячеек StatusCells Редакторы столбцов Visual Studio, показанные на рис. 6.4 и 6.5. Для поддержки этого нужно реализовать специальный тип столбца, который будет распознаваться конструктором. Раз вы реализуете свой собственный тип столбца, в нем можно предусмотреть способ задания того, каким по умолчанию должно быть значение Statuslmage Для добавляемых новых строк. Реализация класса StatusColumn Показана в листинге 6.5.

Из реализации StatusColumn Можно видеть, что прежде всего нужно произвести свой класс от DataGridViewColumn. Затем вы реализуете конструктор по умолчанию, который передает экземпляр вашего специального класса ячейки конструктору базового класса. Тем самым в свойстве CellTempiate Базового класса устанавливается данный тип ячейки, который становится типом ячеек для любых строк, добавляемых к сетке, содержащей ваш тип столбца. Далее класс определяет открытое свойство с именем DefaultStatus. Оно позволяет любому клиенту, использующему этот тип столбца, задать, какое из трех значений Statuslmage Будет отображаться по умолчанию, если никакого значения явным образом не задано, ни через привязку данных, ни посредством программной установки значения ячейки. Установщик для этого свойства модифицирует поле, которое отслеживает текущее значение по умолчанию. К свойству DefaultStatus Обращается метод StatusCell. GetFormattedValue, Описанный выше.

Состыкованные виды дерева и списка

b это означает что он

На форму был также добавлен элемент управления ListView, А его свойство Dock Установлено равным Fill. Это означает, что он будет заполнять остаток центральной части формы. В данном случае, поскольку здесь нет других элементов управления, состыкованных сверху, снизу или справа, он заполнит всю оставшуюся часть формы. С левой стороны он будет достигать границы элемента управления дерева, который был состыкован слева. Если бы на форме были другие состыкованные элементы управления, они прикрепились бы к соответствующим границам и затем попытались расшириться вплоть до смежных границ. Если вы спланируете свою форму таким образом, размер ее двух частей нельзя будет изменять, поэтому для такого рода планировки вы обычно будете применять SplitContainer . Тогда и Treeview, И ListView Станут дочерними элементами контейнеров в SplitContainer И могут быть состыкованы по центру , Заполняя отведенные им части формы по обе стороны разделителя. Когда вы выбираете на форме элемент управления и выбираете в окне Properties свойство Dock, Открывается графический редактор свойства, показанный на рис. В. 17.

Важное значение имеет порядок, в котором вы помещаете элементы управления на форму и устанавливаете их свойства Dock. Если в тот момент, когда элемент управления пытается расшириться до сторон, примыкающих к той, с которой он состыкован, на его пути оказывается другой, уже состыкованный, элемент управления, то он расширится только до кромки этого другого элемента управления. Поэтому, если вы помещаете на форму один элемент управления и устанавливаете его свойство Dock Равным Тор, А затем помещаете на форму другой элемент управления, также устанавливая его свойство Dock Равным Тор, То второй элемент управления будет состыкован с низом первого, а первый элемент управления — с верхом формы. Действуя подобным образом, вы можете создавать при помощи стыковки довольно сложные планировки. Однако поместить все элементы управления на форму в правильном порядке и нужным образом установить их свойства Dock Может оказаться непростым делом.

Метод AddNew

метод b addnew b возвращает

Метод AddNew Позволяет добавить новый элемент непосредственно и получить обратно ссылку на добавленный элемент, позволяющую редактировать его свойства. Метод AddNew Возвращает экземпляр того типа, на который настроен источник привязки. Если до вызова AddNew Тип не был установлен, будет добавлен экземпляр типа Object, Что довольно бесполезно. Поэтому вызывать AddNew Имеет смысл только после того, как будет установлено свойство DataSource Или при помощи метода Add В список будет добавлен первый объект конкретного типа. Вызов AddNew Инициирует вызов метода EndEdit и фиксирует все изменения в текущей строке нижележащего источника данных. Текущим становится новый элемент, добавленный вызовом AddNew. Наконец, AddNew Возбуждает событие AddingNew, Которое можно использовать для инициализации нового объекта значениями по умолчанию, либо вы можете для нового объекта действительно создавать объект и возвращать его через обработчик события, как показано

В листинге 4.4 на событие источника привязки AddingNew Подписывается обработчик события OnAddingNew. Обратите внимание, что при подписке на событие в конструкторе формы не создается явным образом новый объект делегируемого типа, а применяется синтаксическая форма C# для вывода делегата. Этот новый элемент языка C# обеспечивает более компактную нотацию создания делегатов для обработчиков событий или параметров возвратно-вызываемых методов. Обработчик AddingNew Конструирует новый объект и возвращает его через аргумент события, а затем код в обработчике события Load Модифицирует свойство этого объекта, устанавливая значение, отличное от значения по умолчанию.

Удалить элементы из коллекции данных, содержащейся В Источнике привязки, вы можете также при помощи методов Remove И RemoveAt. Метод Remove Принимает ссылку на объект и ищет в списке экземпляр этого объекта, и если он найден, удаляет его. Метод RemoveAt Принимает индекс и удаляет элемент, находящийся в указанной позиции. Удалить из списка сразу все элементы можно вызовом метода Clear.

Интерфейс ICancel Add New

если коллекция поддерживает транзакционное добавление

Для поддержки такого сценария был определен интерфейс ICancelAddNew, Позволяющий коллекции выносить решение о принятии либо отклонении нового элемента, добавленного к коллекции посредством методов этого интерфейса. Если коллекция поддерживает транзакционное добавление элементов, в ней должен быть реализован интерфейс ICancelAddNew. Привязанные элементы управления могут тогда вызывать EndNew, Чтобы фиксировать транзакцию добавления нового элемента, либо CancelNew , чтобы отменить добавление. Это позволяет элементу управления вызвать метод списка AddNew, Получить от него новый элемент и начать установку значений нового объекта. Если код вызовет CancelNew С индексом добавленного элемента, новый объект может быть отброшен, не будучи действительно добавленным в коллекцию. Если код вызовет EndNew С этим индексом или произведет над коллекцией какую-то другую операцию, добавление будет зафиксировано. Самому объекту совершенно не нужно знать о своем промежуточном характере принадлежности к коллекции; всем распоряжается сама коллекция.

Такое поведение несколько отличается от того, что можно было бы ожидать. В мире распределенных транзакций с базами данных подразумевается, что вы должны явно фиксировать транзакцию, иначе она будет отменена. В случае интерфейса ICancelAddNew Поведением по умолчанию в соответствии с контрактом, специфицированным инфраструктурой Framework, является фиксация, даже если EndNew Не будет вызван явно. Таким образом, вставка или удаление других элементов, как и установка в качестве текущего другого элемента коллекции, рассматривается как операция, снимающая фокус ввода с добавляемого элемента и фиксирующая его в коллекции. Как класс BindingList, Рассматриваемый в главе 9, так и класс BindingSource Реализуют этот интерфейс для коллекций, которыми они управляют. Поскольку обобщенный класс BindingList Не может знать, что делать с транзакционной семантикой вызовов AddNew Или CancelNew, То для подходящей к вашему сценарию их реализации вам нужно будет произвести от BindingList Новый класс, заменив в нем методы AddNewCore И CancelNewCore Базового класса.