Опубликован: 08.07.2011 | Уровень: для всех | Доступ: платный
Лекция 8:

Разработка многофункциональных бизнес-приложений

Еще одним возможным вариантом визуализации данных в DataGrid является использование группировки по определенному полю. Предположим, что требуется провести группировку по должности сотрудников. Для этого необходимо в XAML-описание объекта DomainDataSource добавить свойство GroupDescriptors, указав для атрибута PropertyPath, который определяет свойство группировки, значение поля, по которому будет проводиться группировка – Title.Title1.

<riaControls:DomainDataSource AutoLoad="True" 
	d:DesignData="{d:DesignInstance my:Employee, CreateList=true}" 
	Height="0" Width="0"
	LoadedData="employeeDomainDataSource_LoadedData"
	Name="employeeDomainDataSource"
	QueryName="GetEmployeesQuery" >
	<riaControls:DomainDataSource.DomainContext>
		<my1:EmployeeDomainContext />
	</riaControls:DomainDataSource.DomainContext>
	<riaControls:DomainDataSource.GroupDescriptors>
		<riaControls:GroupDescriptor PropertyPath="Title.Title1"/>
	</riaControls:DomainDataSource.GroupDescriptors>
</riaControls:DomainDataSource>

На рис. 10.28 приведены результаты работы приложения с группировкой сотрудников по должности. В списке сотрудников для каждой должности указывается количество записей в группе, группу можно свернуть и развернуть. Так на рис. 10.28 развернутой является только группа, соответствующая должности "Начальник клиентского отдела".

Реализация группировки на странице Сотрудники

увеличить изображение
Рис. 10.28. Реализация группировки на странице Сотрудники

Следующим этапом разработки приложения является организация поиска/фильтрации данных по фамилии сотрудников и по должности.

Вначале модифицируем макет страницы EmployeePage. Добавим в сетку LayoutRoot две строки и три столбца.

Контейнер BusyIndicatorLoadData поместим во второй строке, сетки LayoutRoot, объединив для этого три столбца.

<local:BusyIndicator x:Name="BusyIndicatorLoadData" 
	Grid.Row="1" Grid.ColumnSpan="3" ...>

В первой строке и колонки LayoutRoot разметим объект TextBlock с текстом "Список сотрудников".

Во второй колонке первой строки LayoutRoot поместим элементы управления необходимые для задания параметров фильтрации данных: текстовые блоки с текстами "Поиск", "По фамилии" и "По должности", блок для ввода фамилии textBoxSurname и элемент контроля AutoCompleteBox для ввода должности. Все перечисленные элементы контроля скомпонованы в сетке gridSearch, которая помещена в рамку borderSearch. XAML-описание фрагмента страницы Сотрудники сетки gridSearch, визуализирующей элементы контроля для поиска данных по сотрудникам, приведены в приложении.

Для фильтрации данных по фамилии сотрудника в XAML-описание объекта DomainDataSource необходимо добавить объект FilterDescriptors, который представляет описание фильтра для операций запроса в DomainDataSource объекте.

<riaControls:DomainDataSource.FilterDescriptors>
	<riaControls:FilterDescriptor Operator="StartsWith" 
		PropertyPath="LastName" 
		Value="{Binding ElementName= textBoxLastName, Path=Text}" />
</riaControls:DomainDataSource.FilterDescriptors>

Свойство Operator задает операцию фильтрации, которая определяется элементами перечисления FilterOperator, возможные значения которых приведены в табл. 8.4, а свойство PropertyPath определяет атрибут фильтрации.

Таблица 10.4. Значения перечисления FilterDescriptors
Значение оператора фильтрации Описание действий
Contains Значение должно содержать значение фильтра.
EndsWith Значение должно заканчиваться значением фильтра.
IsContainedIn Значение данных должны содержаться в значении фильтра.
IsEqualTo Значение должно быть равно значению фильтра.
IsGreaterThan Значение должно быть больше, чем значение фильтра.
IsGreaterThanOrEqualTo Значение должно быть больше или равно значению фильтра.
IsLessThan Значение должно быть меньше значения фильтра.
IsLessThanOrEqualTo Значение должно быть меньше или равно значению фильтра.
IsNotEqualTo Значение должно отличаться от значения фильтра.
StartsWith Значение должно начинаться с символов, заданных в фильтре.

В созданном фильтре для фамилии сотрудника использован оперетор StartsWith, который обеспечивает фильтрацию по первым буквам фамилии сотрудника. Результаты тестирования режима фильтрации по фамилии сотрудника приведены на рис. 10.29.

Реализация фильтрации по фамилии

увеличить изображение
Рис. 10.29. Реализация фильтрации по фамилии

При разработки процесса фильтрации по должности рассмотрим как можно добавлять новые источники данных.

В папку DomainModel добавим класс TitleEmployee для формирования данных о должности сотрудников, имеющихся в сущности Employee.

public class TitleEmployee
{
    [Key]
    public string Title { set; get; }
}

Свойство Title снабжено атрибутом [ Key ] для обеспечения возможности формирования полей новой сущность на базе этого класса.

В класс сервиса данных EmployeeDomainService добавим метод GetTitlesEmployee() для получения списка должностей сотрудников.

public IQueryable<TitleEmployee> GetTitlesEmployee()
{
    return this.ObjectContext.Employees.Select(e => new TitleEmployee 
	{ Title = e.Title.Title1 }).Distinct();
}

После проведенных изменений в серверной части проекта необходимо модифицировать клиентскую часть приложения. Добавим в XAML-описание страницы EmployeePage новый источник данных, предоставляющий доступ клиента к списку должностей сотрудников.

<riaControls:DomainDataSource AutoLoad="True" 
	d:DesignData="{d:DesignInstance my1:TitleEmployee, CreateList=true}" Height="0"
	LoadedData="TitleEmployeeDomainDataSource_LoadedData"  Name="titleEmployeeDomainDataSource"
	QueryName="GetTitlesEmployeeQuery" Width="0">
	<riaControls:DomainDataSource.DomainContext>
		<my1:EmployeeDomainContext />
	</riaControls:DomainDataSource.DomainContext>
</riaControls:DomainDataSource>

Источник данных titleEmployeeDomainDataSource формирует список должностей с помощью метода GetTitlesEmployeeQuery() домена сервиса данных.

Для ввода должности при фильтрации формы используется элемент управления AutoCompleteBox, источником привязки которого служит объект данных titleEmployeeDomainDataSource, значение для данного элемента определяются полем Title.

<input:AutoCompleteBox Grid.Row="2" Grid.Column="1" Name="FilterText"
	HorizontalAlignment="Left"
	ValueMemberBinding="{Binding Title}" 
	ItemsSource="{Binding ElementName=titleEmployeeDomainDataSource, 
				Path=Data}"
	TextChanged ="FilterText_TextChanged"
	Margin="20,2,20,2" Height="23" Width="300"/>

Элемент управления AutoCompleteBox поддерживает формирование подсказки при вводе первых символов слова, если оно имеется в источнике данных.

В заключении процесса проектирования функции фильтрации данных по должности необходимо в источнике данных employeeDomainDataSource добавить в объект FilterDescriptors XAML-описание фильтра.

<riaControls:FilterDescriptor PropertyPath="Title.Title1" 
	Operator="IsEqualTo" Value="{Binding ElementName=FilterText, Path=Text}" />
Александр Петров
Александр Петров

При загрузке данных из БД возникает исключение InvalidOperationException с сообщением: Элемент коллекции должен быть пустым перед использованием ItemsSource. Знаю, что для заполнения DataGrid можно использовать коллекции Items или ItemsSource, но одновременно их использовать нельзя: если задано значение для свойства ItemsSource и в коде C# добавляется элемент в Items, возникает исключение. 
Вопрос, как отследить и отключить добавление элемента в Items?

Максим Спиридонов
Максим Спиридонов

В пятой лекции на второй странице в компиляторе выскакивает ошибка в строчке :

ObjectQuery<Employee> employees = DataEntitiesEmployee.Employees;

Ошибка CS0029

Не удается неявно преобразовать тип "System.Data.Entity.DbSet<WpfApplProject.Employee>" в "System.Data.Entity.Core.Objects.ObjectQuery<WpfApplProject.Employee>".

в using прописал все как положено, здесь похоже именно с преобразованием типов проблемы

Igor Chelyadinski
Igor Chelyadinski
Беларусь, Минск, №54, 2013
Валентина Алешина
Валентина Алешина
Россия