При загрузке данных из БД возникает исключение InvalidOperationException с сообщением: Элемент коллекции должен быть пустым перед использованием ItemsSource. Знаю, что для заполнения DataGrid можно использовать коллекции Items или ItemsSource, но одновременно их использовать нельзя: если задано значение для свойства ItemsSource и в коде C# добавляется элемент в Items, возникает исключение. |
Взаимодействие приложения с базой данных
Привязка выпадающего списка
Привязка данных к колонке типа DataGridComboBoxColumn требует определенной подготовительной работы. В таблице Employee модели данных хранится не текстовое значение должности сотрудника, а внешний ключ для таблицы Title, где находится наименование должности. В EDM-модели можно получить значение атрибута из связанных таблиц. В нашем случае для таблицы Employee имеется атрибут Title.Title1, который посредством имеющихся связей в модели обеспечивает доступ к таблице Title из таблицы Employee. Это можно использовать для просмотра данных по сотруднику, но при редактировании данных необходимо обеспечить выбор должности для сотрудника из списка должностей, которые определены в таблице Title. И это невозможно сделать при привязке колонки Должность к полю Title.Title1.
Для обеспечения возможности работы с коллекцией в таблицы Title в приложении добавим в проект папку Model и в ней создадим класс ListTitle.
public class ListTitle: ObservableCollection<Title> { public ListTitle() { ObjectQuery<Title> titles = PageEmployee.DataEntitiesEmployee.Titles; var queryTitle = from title in titles select title; foreach (Title titl in queryTitle) { this.Add(titl); } } }
Класс ListTitle наследуется от класса обобщенной коллекции ObservableCollection<T> и его назначение создавать коллекцию объектов Title. Поле titles является запросом типа ObjectQuery<Title>. Данному полю присваивается свойство Titles контекста данных DataEntitiesEmployee, который определен в классе PageEmployee. В классе ListTitle не рекомендуется создавать собственный контекст данных, а лучше использовать контекст, созданный в классе PageEmployee. Именно поэтому свойства DataEntitiesEmployee объявлено в классе PageEmployee статическим.
Запрос LINQ получает данные из базы TitlePersonal в поле queryTitle и затем в цикле foreach формируется коллекция класса ListTitle.
Для использования класса ListTitle в XAML-документе класса PageEmployee необходимо объявить данный класс как ресурс. При этом нужно подключить пространство имен WpfApplProject.Model.
xmlns:core ="clr-namespace:WpfApplProject.Model"
Затем определим ресурс страницы с ключом listTitle.
<Page.Resources> <core:ListTitle x:Key="listTitle" /> </Page.Resources>
Далее модифицируем XAML описание для типа DataGridComboBoxColumn.
<DataGridComboBoxColumn Header="Должность" ItemsSource="{Binding Source={StaticResource listTitle}}" DisplayMemberPath="Title1" SelectedValueBinding="{Binding Path=TitleID, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" SelectedValuePath="ID" />
Источник выпадающего списка задается как статический ресурс {StaticResource listTitle}. Выводимое в ячейки колонки поле должно соответствовать полю Title1 таблицы Title EDM-модели DisplayMemberPath="Title1"). Выбираемый в списке параметр (SelectedValueBinding) должен быть привязан к полю TitleID таблицы Employee.
SelectedValueBinding="{Binding Path=TitleID, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
Выбор в свойства SelectedValueBinding производится по пути определенному свойством SelectedValuePath (SelectedValuePath="ID").
При запуске приложения страница PageEmployee принимает вид, показанный на рис. 5.8.
Ячейка столбца типа DataGridComboBoxColumn имеет три представления ( рис. 5.9). Если ячейка не выделена, то представление обычное текстовое ( рис. 5.9а). При выделении ячейки прорисовывается представление ComboBox ( рис. 5.9б). При раскрытии списка появляется список элемента ComboBox ( рис. 5.9в).
Привязка даты
При привязке даты к колонке "Дата рождения" ставилась задача для невыделенной ячейки представлять дату в виде цифр дня, месяца и года, разделенных точками, а для выделенной ячейки – использовать класс для выбора даты.
Решение данной задачи осуществлено с помощью разработки двух шаблонов данных DataTemplate.
В первом шаблоне, для которого задан ключ DateTemplate, используется элемент управления TextBlock, свойство Text которого привязывается к атрибуту BirstDate таблицы Employee. Данные в привязке форматируются свойством StringFormat и строковые данные выравниваются по центру. Этот шаблон используется для визуализации данных в режиме их просмотра.
<DataTemplate x:Key="DateTemplate" > <TextBlock Text="{Binding BirstDate, StringFormat={}{0:dd\.}{0:MM\.}{0:yyyy}}" VerticalAlignment="Center" HorizontalAlignment="Center" /> </DataTemplate>
Второй шаблон с ключом EditingDateTemplate использует класс DatePicker. Этот шаблон используется в режиме редактирования данных.
<DataTemplate x:Key="EditingDateTemplate"> <DatePicker SelectedDate="{Binding BirstDate, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" /> </DataTemplate>
Разработанные шаблоны необходимо добавить к ресурсам в XAML-документ страницы PageEmployee.
<DataGridTemplateColumn Header="Дата рождения" CellTemplate="{StaticResource DateTemplate}" CellEditingTemplate="{StaticResource EditingDateTemplate}" />
Невыделенную ячейку колонки ( CellTemplate ) свяжим с ресурсом DateTemplate, а редактируемую ячейку ( CellEditingTemplate ) – с ресурсом EditingDateTemplate.
При запуске приложения страница PageEmployee принимает вид, показанный на рис. 5.10.
Ячейка столбца для отображения даты типа DataGridTemplateColumn имеет три представления ( рис. 5.11). Если ячейка не выделена, то представление обычное текстовое ( рис. 5.11а). При выделении ячейки прорисовываетася свернутое содержание класса DatePicker ( рис. 5.11б). При щелчке на ячейке появляется календарь ( рис. 5.11в).