При загрузке данных из БД возникает исключение InvalidOperationException с сообщением: Элемент коллекции должен быть пустым перед использованием ItemsSource. Знаю, что для заполнения DataGrid можно использовать коллекции Items или ItemsSource, но одновременно их использовать нельзя: если задано значение для свойства ItemsSource и в коде C# добавляется элемент в Items, возникает исключение. |
Разработка Silverlight-приложений
Редактирование данных
Для редактирования данных по сотруднику необходимо обеспечить возможность изменения детальных данных, что реализуется нажатием кнопки Редактировать, которая задает свойству IsReadOnly элементов управления TextBox и свойству IsEnabled элементов управления ComboBox и DatePicker значение true. С учетом того, что для элементов управления детальными данными выполнена двусторонняя привязка данных ( Mode=TwoWay ), то изменения в детальных данных будут приводить к изменению данных в контексте сущностей PersonalEntities, связанных со списком listBoxEmployees. После редактирования данных по сотруднику необходимо проведенные изменения сохранить в базе данных. Для этого модифицируем метод Save_Click, добавив в него следующую строку:
context.BeginSaveChanges(SaveChangesOptions.Batch, OnChangesSaved, context);
Измененный код метода Save_Click будет иметь следующий вид:
private void Save_Click(object sender, RoutedEventArgs e) { context.BeginSaveChanges(SaveChangesOptions.Batch, OnChangesSaved, context); ReadOnly(false); ButtonIsEnabled(true); listBoxEmployees.IsEnabled = true; }
Метод BeginSaveChanges() класса DataServiceContent запускает асинхронную операцию сохранения данных, изменение которых были проведены в контексте сущностей PersonalEntities. Перечисление SaveChangesOptions.Batch определяет, что все проведенные изменения сохраняются в составе одного пакетного запроса. Вторым параметром метода BeginSaveChanges() является делегат, который ссылается на метод OnChangesSaved(). Метод OnChangesSaved() обрабатывает результат этой асинхронной операции путем вызова метода EndSaveChanges(), анализа возвращаемых объектов OperationResponse и печати кодов состояния ответа.
private void OnChangesSaved(IAsyncResult result) { Dispatcher.BeginInvoke(() => { context = result.AsyncState as PersonalEntities; try { WriteOperationResponse(context.EndSaveChanges(result)); } catch (DataServiceRequestException ex) { MessageBox.Show( WriteOperationResponse(ex.Response)); } catch (InvalidOperationException ex) { MessageBox.Show(ex.Message); } } ); }
Метод WriteOperationResponse() обеспечивает формирование информации при сохранении данных.
private string WriteOperationResponse(DataServiceResponse response) { string mes = string.Empty; int i = 1; if (response.IsBatchResponse) { mes = string.Format("Коды серии операций сохранения: {0}\n", response.BatchStatusCode); } foreach (ChangeOperationResponse change in response) { mes += string.Format("\tИзменение {0} code: {1}\n", i.ToString(), change.StatusCode.ToString()); if (change.Error != null) { string.Format("\tИзменение {0} error: {1}\n", i.ToString(), change.Error.Message); } i++; } return mes; }
Проведенные изменения обеспечивают для разрабатываемого приложения возможность редактирования данных и сохранение изменений в базе данных.
Создание новых данных по сотруднику
Для создания новых записей по сотрудникам в базе данных изменим код метода New_Click().
private void New_Click(object sender, RoutedEventArgs e) { Employee newEmployee = Employee.CreateEmployee(0, "не задано", "не задано", 0, "не задано"); newEmployee.Access = "не задано"; newEmployee.EmployeeStatus = 0; newEmployee.NetName = "guest"; newEmployee.FirstDate = DateTime.Now; try { context.AddToEmployees(newEmployee); context.BeginSaveChanges(SaveChangesOptions.Batch, OnChangesSaved, context); employees.Add(newEmployee); int count = listBoxEmployees.Items.Count; listBoxEmployees.SelectedIndex = count - 1; ButtonIsEnabled(false); ReadOnly(true); listBoxEmployees.IsEnabled = false; } catch (DataServiceRequestException ex) { MessageBox.Show("Ошибка добавления нового сотрудника в базу данных"); } }
Вначале для класса Employee модели сущностей Personal создаем новый экземпляр newEmployee с помощью метода CreateEmployee():
Employee newEmployee=Employee.CreateEmployee(0, "не задано","не задано",0,"не задано");
Метод CreateEmployee() автоматически сгенерирован при создании EDM-модели сущностей и в качестве параметров использует только обязательные поля таблицы Employee базы данных Personal. Следующие строки кода предназначены для задания необязательных полей таблицы Employee ( Access, EmployeeStatus, NetName и FirstDate ):
newEmployee.Access = "не задано"; newEmployee.EmployeeStatus = 0; newEmployee.NetName = "guest"; newEmployee.FirstDate = DateTime.Now;
Добавление новой сущности newEmployee в модель Personal производится следующей строкой кода:
context.AddToEmployees(newEmployee);
при этом используется метод AddToEmployees().
Затем посредством метода BeginSaveChanges() класса DataServiceContent запускаем сохранение данных в контексте сущностей PersonalEntities.
context.BeginSaveChanges(SaveChangesOptions.Batch, OnChangesSaved, context);
Для продолжения работы приложения необходимо внести изменения в коллекцию employees.
employees.Add(newEmployee);
и установить фокус в списке listBoxEmployees на созданной записи:
int count = listBoxEmployees.Items.Count; listBoxEmployees.SelectedIndex = count - 1;
Удаление данных по сотруднику
Для удаления данных по сотруднику в базе данных необходимо определить экземпляр удаляемого объекта из списка listBoxEmployees.
Employee emp = (Employee)listBoxEmployees.SelectedItem;
Затем удалим экземпляр класса Employee из контекста сущностей PersonalEntities с помощью метода DeleteObject().
context.DeleteObject(emp);
После изменения индекса выделения в списке listBoxEmployees необходими удалить экземпляр emp класса Employee из коллекции employees.
listBoxEmployees.SelectedIndex = listBoxEmployees.SelectedIndex == 0 ? 1 : listBoxEmployees.SelectedIndex - 1; employees.Remove(emp);
Посредством метода BeginSaveChanges() класса DataServiceContent запускаем сохранение изменений при удалении данных из контекста сущностей PersonalEntities.
context.BeginSaveChanges(SaveChangesOptions.Batch, OnChangesSaved, context);
Окончательный код метода Delete_Click() будет иметь следующий вид.
private void Delete_Click(object sender, RoutedEventArgs e) { Employee emp = (Employee)listBoxEmployees.SelectedItem; MessageBoxResult result = MessageBox.Show("Удалить сотрудника: " + emp.EmployeeSurname + " " + emp.EmployeeName + " " + emp.EmployeePatronymic, "Предупреждение", MessageBoxButton.OKCancel); if (result == MessageBoxResult.OK) { context.DeleteObject(emp); listBoxEmployees.SelectedIndex = listBoxEmployees.SelectedIndex == 0 ? 1 : listBoxEmployees.SelectedIndex - 1; employees.Remove(emp); context.BeginSaveChanges(SaveChangesOptions.Batch, OnChangesSaved, context); } }
Процесс разработки Silverlight-приложения, проведенный в лекциях "Взаимодействие приложения с базой данных" и "Разработка приложения на базе WPF" настоящего пособия, отражает основные этапы создания корпоративных веб-приложений, имеющих клиент-серверную архитектуру.
Ключевые термины
Технология Silverlight , браузер, веб-сервер, модель "сущность-связь", модель ADO.NET, службы WCF Data Services, язык LINQ, привязка данных, шаблон DataTemplate, редактирование данных, создание новых данных, удаление данных.
Silverlight, Entity Data Model, EDM, .NET Framework, DataService, UserControl, DataServiceContext, DataServiceQuery, BeginExecute, Binding, Path, BeginSaveChanges, SaveChangesOptions, OnChangesSaved, Dispatcher, BeginInvoke, ChangeOperationResponse, DeleteObject.
Краткие итоги
Проиллюстрированы возможности построения корпоративного Silverlight-приложения, включающего серверную часть на базе веб-приложение ASP.NET, источник данных в виде базы данных для СУБД SQL Server, службу данных, клиентскую часть системы, позволяющую просматривать, редактировать, удалять и создать данные по сотрудникам предприятия.
Ресурсы для углубленного изучения
- Silverlight // http://msdn.microsoft.com/ru-ru/library/cc838158(v=VS.95).aspx.
- [ [ 2 ] ], стр. 5 – 134.
- [ [ 3 ] ], стр. 17 - 238
- [ [ 5 ] ], стр. 17 – 85.
- [ [ 6 ] ], стр.1005 – 1024, 1234 – 1256.
- [ [ 9 ] ], стр. 906 - 960
Вопросы для самопроверки
- Поясните назначение технологии Silverlight.
- Какие преимущества имеет технология Silverlight?
- Какие особенности имеет технология Silverlight?
- Поясните назначение службы WCF Data Services.
- Какой набор клиентских библиотек включен в состав служб WCF Data Services?
- Каким способом для клиентского приложения Silverlight обеспечивается доступ к серверным службам WCF Data Services?
- Как можно выполнить запрос к службе данных из клиентского приложения?
- Поясните назначение класса DataServiceContext.
- Поясните назначение класса DataServiceQuery<T>.
- Почему необходимо использовать метод BeginExecute() для выполнения запроса службы данных WCF ?
- Поясните назначение метода LoadAsync.
- Как осуществляется привязка интерфейсных элементов к источнику данных службы WCF Data Services?
- Как осуществляется привязка данных к элементу контроля ComboBox?
- Как осуществляется привязка данных для связанных таблиц источника данных?
- Как можно управлять доступностью элементов контроля в Silverlight приложении?
- Поясните назначение метода BeginSaveChanges().
- Поясните назначение метода OnChangesSaved().
- С помощью какого метода можно создать новую запись в источнике данных службы WCF Data Services?
- Какой метод службы WCF Data Services используется для удаления данных источнике данных?