Работа с DataGrid в Silverlight с использованием ADO.NET и WCF

ОГЛАВЛЕНИЕ

Ключевым аспектом любого бизнес-приложения является возможность переноса информации из базы данных в пользовательский интерфейс. Хотя существует множество вопросов, которые необходимо обсудить, данная статья пройдет через самый короткий путь, чтобы продемонстрировать при помощи простейшей технологии один из способов переноса информации из одного места в другое.

Цели

Непосредственной целью данной статьи будет реализация извлечения информации из базы данных SQLServer, при помощи оператора Where и предоставления ее посредством веб-сервиса с использованием WCF-SOAP. Информация будет затем использована приложением Silverlight , которое отобразит ее в элементе управления DataGrid. В общем, цель заключается в демонстрации взаимодействия данных технологий для упрощения получения информации.

Шаг 1 – База данных

Для начала вам понадобится база данных AdventureWorks, которую вы можете найти на Codeplex. Будьте внимательны при загрузке, так как вам будет необходима соответствующая версия (2005 или 2008) в зависимости от версии имеющегося SqlServer. Если у вас есть в наличии только SqlExpress и Visual Studio, то одним из способов создания соединения данных с файлом является открытие окна Server Explorer - щелкнув правой кнопкой мыши по Data Connection и выбрав пункт “Add Connection” (Добавить соединение). Затем нажмите на Data Source->Change и выберите пункт SQL Server Database File (Файл базы данных SQL Server).

В диалоговом окне добавления соединения (Add Connection) щелкните по кнопке Browse и выберите файл Adventureworks.mdf (обычно установлен в : C:\Program Files (x86)\Microsoft SQL Server\MSSQL.1\MSSQL\Data).  Проверьте свое соединение при необходимости.

Шаг 2 – Создание нового проекта

Создайте новый проект Silverlight и назовите его EntitiesWebSvcGrid, при этом примите стандартную опцию типа проекта в качестве веб-приложения (ASP.NET Web Application). Вы можете называть свои проекты и объекты так, как вы решите нужным, но мы будем использовать определенные названия для удобства в объяснении.

Рисунок 9-1. Веб-проект

Visual Studio создаст одно решение с двумя проектами:

  • EntitiesSvcGrid  (проект Silverlight )
  • EntitiesSvcGrid.Web (веб-проект)

Второй проект будет содержать модель ADO.NET и веб-сервис, в то время как первый будет содержать DataGrid из Silverlight.

Шаг 3 – Добавление модели ADO.NET

Чтобы создать модель данных (Data Model) щелкните правой кнопкой мыши по веб-проекту и выберите пункт Add New. После выберите Ado.Net Entity Data Model,назовите ее EmployeeDataModel.edmx и нажмите кнопку добавления (Add).

В следующем диалоговом окне щелкните по кнопке "Generate from Database"– это создаст модель данных, сохранив вам море времени. Следующее диалоговое окно попросит вас выбрать желаемый тип соединения,

Рисунок 9-2. Выбор источника данных

Как только соединение будет осуществлено и будет получена структура данных, вас попросят выбрать таблицы, представления и хранимые процедуры, которые вы хотели бы включить в вашу модель. Для данного примера мы выберем всего одну таблицу для простоты: Employee

Рисунок 9-3. Выбор объектов данных

При нажатии на кнопку Finish ваша модель данных будет создана. Уделите несколько минут на изучение результата. Обратите внимание на то, что может появиться окно Visual Studio названное Mapping Details. Откройте его и пусть оно занимает пол экрана - его также стоит исследовать.

Рисунок 9-4. Сопоставление деталей

 

Шаг 4 Создание веб-сервиса

Создав модель данных, мы можем приступить к созданию  веб-сервиса для того, чтобы информация была доступна приложению Silverlight, работающему со стороны клиента. У нас есть несколько вариантов выполнения задуманного, но сейчас мы будем  использовать модель WCF/SOAP посредством шаблона Silverlight-aware. Заново щелкните правой кнопкой мыши по веб-проекту и выберите Add… New Item, на этот раз выбрав Silverlight-Enabled WCF Service. Назовите новый сервис EmployeeWebService и нажмите OK. Откройте EmployeeWebService.svc.cs, где вы найдете метод-пустышку DoWork, который вы измените для того, чтобы он получал список сотрудников.

[ServiceContract( Namespace = "" )]
[AspNetCompatibilityRequirements( RequirementsMode =
   AspNetCompatibilityRequirementsMode.Allowed )]
public class EmployeeWebService
{
    [OperationContract]
    public  List<Employee> GetEmployees()
    {
      AdventureWorks_DataEntities ds =
         new AdventureWorks.DataEntities();
       return ds.Employee.Where( emp => emp.SalariedFlag == true ).ToList();
    }
}

Данный код стоит исследовать. Первая строка метода GetEmployees создает экземпляр DataEntity, который мы определили ранее. Вторая строка запрашивает экземпляр данных об объектах Employee, но поскольку их слишком  много, то мы добавим оператор where, использующий лямбда-выражение для того, чтобы уменьшить, возвращается набор и затем вызывает ToList() по отношению к полученному списку, при этом эффективно конвертируя результат в List<Employee>.

Использование лямбда-выражения в операторе Where

Используемое выражение для сокращения списка сотрудников является лямбда-выражением

emp => emp.SalariedFlag == true

Существует несколько способов интерпретации данного выражения, но простым объяснением будет “пусть emp - это все объекты сотрудников, чье свойство SalariedFlag оценивается как true.”


Привязка к DataGrid

Чтобы сохранить простоту пользовательского интерфейса мы просто перетащим DataGrid из инструментария на Page.xaml как и другие элементы интерфейса данного приложения. Перетаскивание элемента имеет некоторое преимущество перед заданием вручную - Visual Studio добавит соответствующее пространство имен.

xmlns:data="clr-namespace:System.Windows.Controls;assembly = System.Windows.Controls.Data"  

Добавьте название для вашей сетки (x:Name=”dg”) и уберите высоту и ширину окружающего пользовательского элемента управления (UserControl). Здесь я привел исходный код для Page.xaml

<UserControl
xmlns:data="clr-namespace:System.Windows.Controls;assembly = System.Windows.Controls.Data"
x:Class="EntitiesSvcGrid.Page"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" >
<Grid x:Name="LayoutRoot" Background="White">  
        <data:DataGrid x:Name="dg" />
</Grid>
</UserControl>

Привязка данных к DataGrid

Завершаем мы все в Page.xaml.cs, где вам необходимо будет привязать данные из веб-сервиса к данным табличной сетки.

Первым шагом будет добавление к этому проекту ссылки на веб-сервис. Для этого щелкните правой кнопкой мыши по ServiceReferences и в диалоговом окне Add Service Reference щелкните по Discover. Созданный ранее веб-сервис (EmployeeWebService) появится в списке. Щелкните по нему и затем переименуйте пространство имен на EmployeeWebService.

Рисунок 9-5. Добавление ссылки на сервис

Нажмите на OK для того, чтобы добавить ссылку на сервис и откройте Page.xaml.cs.

Я склонен к настройке обработчиков в событии Loaded вместо того, чтобы делать это в конструкторе, хотя это может показаться вам старомодным,

using System;
using System.Windows;
using System.Windows.Controls;
 
namespace EntitiesSvcGrid
{
   public partial class Page : UserControl
   {
      public Page()
      {
         InitializeComponent();
         Loaded += new RoutedEventHandler( Page_Loaded );
      }

Нашей задачей теперь будет создание экземпляра клиента веб-сервиса и затем использование данного клиента для вызова метода GetEmployees.

Создание экземпляра клиента очень просто в исполнении,

EmployeeWebService.EmployeeWebServiceClient ws = new  
  EntitiesSvcGrid.EmployeeWebService.EmployeeWebServiceClient();

Хотя приложение Silverlight запускается в обозревателе, мы не можем осуществлять вызовы методов напрямую (вы не должны блокировать обозреватель), нам скорее необходимо осуществлять асинхронные вызовы. Intellisense не только предлагает нам альтернативу в видео асинхронных вызовов, но и не предлагает нам синхронные методы, которые мы создали!

Рисунок 9-6. Асинхронные вызовы


Создание обратного вызова (Callback)

Вы наверняка обратили внимание на предыдущем рисунке, что прямо под методом GetEmployeeAsync Intellisense указывает метод GetEmployeeCompleted. Данный метод вызывается тогда, когда завершается метод Asynchronous,  и, регистрируя данное событие, вы можете получить список сотрудников и привязать их к сетке с данными в вашем обработчике события.

Поэтому файл Page.xaml.cs должен выглядеть следующим образом,

using System;
using System.Windows;
using System.Windows.Controls;
 
namespace EntitiesSvcGrid
{
   public partial class Page : UserControl
   {
      public Page()
      {
         InitializeComponent();
         Loaded += new RoutedEventHandler( Page_Loaded );
      }
 
      void Page_Loaded( object sender, RoutedEventArgs e )
      {
         EmployeeWebService.EmployeeWebServiceClient ws = new
           EntitiesSvcGrid.EmployeeWebService.EmployeeWebServiceClient();
         ws.GetEmployeesCompleted +=
            new EventHandler<EntitiesSvcGrid.EmployeeWebService.
            GetEmployeesCompletedEventArgs>( ws_GetEmployeesCompleted );
         ws.GetEmployeesAsync();
        
      }
 
      void ws_GetEmployeesCompleted(
         object sender,
         EntitiesSvcGrid.EmployeeWebService.GetEmployeesCompletedEventArgs e )
      {
         dg.ItemsSource = e.Result;
      }
   }
}

Задачей обработчика события будет связывание результата Result (полученного при помощи параметра GetEmployeeCompletedEventArgs и который является  типа observableCollection<Employee>), к свойству ItemSource табличной сетки.

Рисунок 9-7. Элемент источника (ItemSource)

 

Обзор результата

Когда вы скомпилируете проект информация будет извлечена из базы данных, и результат будет ограничиваться лямбда-выражением. Он будет доступен посредством веб-сервиса и привязан к элементу управления DataGrid.

Рисунок 9-8. DataGrid

Хотя внешний вид приложения недоработан (к примеру, колонки не имеют названия, и мы не модернизировали пользовательский интерфейс стилями либо шаблонами) вся основная функциональность работает идеально, включая сортировку, к примеру, для колонки с датой, указывающей, когда сотрудник был нанят (HireDate).

Скачать исходный код примеров

Jesse Liberty