При загрузке данных из БД возникает исключение InvalidOperationException с сообщением: Элемент коллекции должен быть пустым перед использованием ItemsSource. Знаю, что для заполнения DataGrid можно использовать коллекции Items или ItemsSource, но одновременно их использовать нельзя: если задано значение для свойства ItemsSource и в коде C# добавляется элемент в Items, возникает исключение. |
Взаимодействие приложения с базой данных
Поиск данных
При больших размерах базы данных по сотрудникам целесообразно, чтобы приложение поддерживало функцию поиска данных, например по фамилии и по должности. Для реализации функций поиска добавим на страницу PageEmployee элементы управления в соответствии с рис. 5.16рис. 5.16.
XAML-описание элементов управления, поддерживающих поиск имеет следующий вид.
<TextBlock Name="TextBlockSurname" Text="Фамилия" /> <TextBlock Name="TextBlockTitle" Text="Должность" /> <TextBox Name="TextBoxSurname" TextChanged="TextBoxSurname_TextChanged"/> <ComboBox Name="ComboBoxTitle" ItemsSource="{Binding Source={StaticResource listTitle}}" DisplayMemberPath="Title1" SelectionChanged="ComboBoxTitle_SelectionChanged"/> <Button Name="ButtonFindSurname" ToolTip="Поиск по фамилии" IsEnabled="False" Click="ButtonFindSurname_Click"> <Image Source="Images/Search.jpg"/> </Button> <Button Name="ButtonFindTitle" ToolTip="Поиск по должности" IsEnabled="False" Click="ButtonFindTitle_Click"> <Image Source="Images/Search.jpg" /> </Button>
Элементы управления размещаем в рамке BorderFind, для которой делаем градиентную заливку. В рамке располагаем сетку gridFind с тремя колонками и строками. Первая строка в объединенных колонках содержит текстовый блок find с текстом "Поиск". Во второй и третьей строках первой колонки размещены текстовые блоки TextBlockSurname и TextBlockTitle соответственно. Во второй колонке размещаются элементы управления для ввода информации: текстовый блок TextBoxSurname (вторая строка) и выпадающий список ComboBoxTitle (третья строка). В третьей колонке размещаются кнопки: для поиска по фамилии ButtonFindSurname (вторая строка) и для поиска по должности ButtonFindTitle (третья строка).
При загрузке страницы PageEmployee рамка BorderFind невидима, так как свойству Visibility задано значение "Hidden". При активизации команды Find из меню или панели инструментов запускается обработчик FindCommandBinding_Executed, который делает рамку ButtonFindTitle видимой ( рис. 5.17).
private void FindCommandBinding_Executed(object sender, ExecutedRoutedEventArgs e) { BorderFind.Visibility = System.Windows.Visibility.Visible; }
Если в текстовом блоке TextBoxSurname не введена информация или в выпадающем списке ComboBoxTitle не сделан выбор, то кнопки ButtonFindSurname и ButtonFindTitle будут недоступны.
При вводе информации в текстовый блок TextBoxSurname запускается обработчик TextBoxSurname_TextChanged, который делает доступной кнопку ButtonFindSurname.
private void TextBoxSurname_TextChanged(object sender, TextChangedEventArgs e) { ButtonFindSurname.IsEnabled = true; ButtonFindTitle.IsEnabled = false; ComboBoxTitle.SelectedIndex = -1; }
При нажатии кнопки ButtonFindSurname запускается обработчик ButtonFindSurname_Click.
private void ButtonFindSurname_Click(object sender, RoutedEventArgs e) { string surname = TextBoxSurname.Text; DataEntitiesEmployee = new TitlePresonalEntities(); ListEmployee.Clear(); ObjectQuery<Employee> employees = DataEntitiesEmployee.Employees; var queryEmployee = from employee in employees where employee.Surname == surname select employee; foreach (Employee emp in queryEmployee) { ListEmployee.Add(emp); } if (ListEmployee.Count > 0) { DataGridEmployee.ItemsSource = ListEmployee; ButtonFindSurname.IsEnabled = true; ButtonFindTitle.IsEnabled = false; } else MessageBox.Show("Сотрудник с фамилией \n"+surname+"\n не найдан", "Предупреждение", MessageBoxButton.OK, MessageBoxImage.Warning); }
В данном обработчике события Click выполняется LINQ запрос на получение данных из базы TitlePersonal в соответствии с заданной фамилией сотрудника.
var queryEmployee = from employee in employees where employee.Surname == surname select employee;
При выполнении запроса по фамилии страница PageEmployee имеет вид, приведенный на рис. 5.18
Найденные данные по сотруднику можно редактировать и удалять.
Если поиск в базе данных не привел к нахождению информации, то выдается информационное сообщение ( рис. 5.19).
Для поиска информации из базы данных по должности сотрудников необходимо сделать выбор из выпадающего списка ComboBoxTitle. В результате выбора срабатывает обработчик ComboBoxTitle_SelectionChanged, который делает доступной кнопку ButtonFindTitle.
private void ComboBoxTitle_SelectionChanged(object sender, SelectionChangedEventArgs e) { ButtonFindTitle.IsEnabled = true; ButtonFindSurname.IsEnabled = false; TextBoxSurname.Text = ""; }
При нажатии на кнопку ButtonFindTitle срабатывает обработчик ButtonFindTitle_Click.
private void ButtonFindTitle_Click(object sender, RoutedEventArgs e) { DataEntitiesEmployee = new TitlePresonalEntities(); ListEmployee.Clear(); Title title = ComboBoxTitle.SelectedItem as Title; ObjectQuery<Employee> employees = DataEntitiesEmployee.Employees; var queryEmployee = from employee in employees where employee.TitleID == title.ID orderby employee.Surname select employee; foreach (Employee emp in queryEmployee) { ListEmployee.Add(emp); } DataGridEmployee.ItemsSource = ListEmployee; }
При запуске данного обработчика выполняется LINQ-запрос к базе данных TitlePersonal для выборки данных по сотрудникам, имеющим заданную должность. На рис. 5.20 приведены результаты поиска трейдеров инвестиционной компании.
Для обновления выводимого списка сотрудников в приложение добавлена функция обновления, которая реализуется командой Refresh. Данная команда добавлена в коллекцию команд страницы PageEmployee.
<Page.CommandBindings> .... <CommandBinding Command="Refresh" Executed="RefreshCommandBinding_Executed" /> ... </Page.CommandBindings>
<MenuItem Header="Обновить" Command="Refresh"/>
<Button Name="Refresh" Margin="5,2,5,2" Command="Refresh" ToolTip="обновить данные по сотрудникам"> <Image Source="Images/Refresh.jpg" ></Image> </Button>
Основное назначение обработчика команды RefreshCommandBinding_Executed – обновление списка ListEmployee.
private void RefreshCommandBinding_Executed(object sender, ExecutedRoutedEventArgs e) { RewriteEmployee(); DataGridEmployee.IsReadOnly = false; isDirty = false; SetUnvisibilityFind(); }
Команда "Обновить" обычно используется после поиска данных или ввода данных по новому сотруднику.
Ключевые термины
Модель "сущность-связь", модель EDM, концептуальная модель, тип сущности, тип ассоциации, привязка данных, проверка ввода данных, правило проверки, поиск данных.
Entity Data Model, EDM, ADO.NET, ObjectContext, ObservableCollection, ObjectQuery, Binding, ValidationRule
Краткие итоги
Рассмотрены вопросы построения EDM-модели в приложении. Выполнена привязка данных к интерфейсным элементам: текстовым, выпадающему списку, дате. Сконструирован код методов взаимодействия приложения с базой данных: редактирование, вставка, удаление данных и поиск данных. На основе пользовательских правил проиллюстриравана возможность проверки данных при их вводе.
Ресурсы для углубленного изучения
- Платформа ADO.NET Entity Framework // http://msdn.microsoft.com/ru-ru/library/bb399572.aspx.
- Привязка данных // http://msdn.microsoft.com/ru-ru/library/cc278072(v=VS.95).aspx.
- [ 1 ] , стр. 315 – 363.
- [ 4 ] , стр. 535 – 588.
- [ 6 ] , стр. 329 – 357, 978 – 1004.
- [ 8 ] , стр. 740 – 779, 832 – 866.
- [ 9 ] , стр. 463 – 492, 857 – 890, 1048 - 1102
Вопросы для самопроверки
- Объясните назначение и основные понятия EDM –модели.
- Какие структуры и типы данных может описывать EDM-модель?
- Какие основные понятия используются в модель EDM для описания структуры данных?
- Поясните содержание и назначение типа сущности в EDM модели.
- Поясните содержание и назначение типа ассоциации в EDM модели.
- Поясните содержание и назначение свойств в EDM модели.
- Как в проекте задается строка соединения с базой данных для EDM модели?
- Для чего необходимо в проекте иметь свойство контекста данных EDM модели?
- Поясните назначение и возможности коллекции типа ObservableCollection<Т>.
- Поясните назначение и возможности класса ObjectQuery<Т>.
- Поясните назначение и возможности свойства UpdateSourceTrigger, используемого при привязке данных.
- Поясните особенности привязки данных к колонкам таблиц типа DataGridComboBoxColumn.
- Поясните особенности привязки данных к колонкам таблиц с помощью шаблона DateTemplate.
- С помощью какого метода фиксируются проведенные изменения в источнике данных?
- Поясните назначение валидации данных.
- Каким требованиям должен соответствовать класс, используемый для валидации данных?
- Какими способами можно реализовать поиск и фильтрацию данных из источника данных?