В этот раз попробуем добавить в приложение какую-нибудь логику и добавить отображение данных.
Обычно я создаю дополнительный проект для слоя бизнес логики, а работа с базой данных осуществляется с помощью Entity Framework.
То есть поступаем так:
Создаем новый Windows Class Library проект BusinessApplication.BLL.
В него добавляетм ADO.NET Entity Data Model.
Не забываем выбрать галочку Pluralize or singularize generated object names.
В этой примере получим такую схему базы данных. В ней есть только одна связь один-ко-многим.
Теперь нам нужно сделать сервис, который будет отдавать Silverlight приложению данные. В папке Services ASP.NET проекта добавляем новый элемент Domain Service Class (перед этим не забываем добавить BLL проект в списко зависимостей Web проекта, и скоспилировать все это вместе).
В мастере выбираем все сущности, ставим галочку на Enable client access. Уже сейчас нас поджидает первая неожиданность:
Мы не можем поставить галочку на Generate associated classes for metadata. Дело в том, что модель данных содержится в другом проекте и, почему-то из-за этого нельзя создать файл с метаданными…
К счастью есть простое решение этой проблемы:
Создаем Domain Service Class с таким же названием в BLL проекте
Для него ставим галочку Generate associated classes for metadata
После этого появятся два файла.
DomainService1.cs - сервис.
DomainService1.metadata.cs – файл с метаданными для сущностей из модели данных.
Теперь можно стереть файл DomainService1.cs из BLL проект и добавить его в Web проект. Таким образом DomainService1.cs будет находиться в папке Services Web проекта, а DomainService1.metadata.cs в BLL проекте.
Файл с метаданными содержит следующий код, но пока мы не будем на нем останавливаться.
namespace BusinessApplication.BLL
{
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Data.Objects.DataClasses;
using System.Linq;
using System.ServiceModel.DomainServices.Hosting;
using System.ServiceModel.DomainServices.Server;
// The MetadataTypeAttribute identifies CustomerMetadata as the class
// that carries additional metadata for the Customer class.
[MetadataTypeAttribute(typeof(Customer.CustomerMetadata))]
public partial class Customer
{
// This class allows you to attach custom attributes to properties
// of the Customer class.
//
// For example, the following marks the Xyz property as a
// required property and specifies the format for valid values:
// [Required]
// [RegularExpression("[A-Z][A-Za-z0-9]*")]
// [StringLength(32)]
// public string Xyz { get; set; }
internal sealed class CustomerMetadata
{
// Metadata classes are not meant to be instantiated.
private CustomerMetadata()
{
}
public int ID { get; set; }
public string Name { get; set; }
public Town Town { get; set; }
public int TownID { get; set; }
}
}
// The MetadataTypeAttribute identifies TownMetadata as the class
// that carries additional metadata for the Town class.
[MetadataTypeAttribute(typeof(Town.TownMetadata))]
public partial class Town
{
// This class allows you to attach custom attributes to properties
// of the Town class.
//
// For example, the following marks the Xyz property as a
// required property and specifies the format for valid values:
// [Required]
// [RegularExpression("[A-Z][A-Za-z0-9]*")]
// [StringLength(32)]
// public string Xyz { get; set; }
internal sealed class TownMetadata
{
// Metadata classes are not meant to be instantiated.
private TownMetadata()
{
}
public EntityCollection<Customer> Customers { get; set; }
public int ID { get; set; }
public string Name { get; set; }
}
}
}
Файл с сервисом содержит код методов Get, Insert, Update, Delete для каждой сущности из модели данных.
namespace BusinessApplication.BLL
{
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Data;
using System.Linq;
using System.ServiceModel.DomainServices.EntityFramework;
using System.ServiceModel.DomainServices.Hosting;
using System.ServiceModel.DomainServices.Server;
// Implements application logic using the MySamplerDBEntities context.
// TODO: Add your application logic to these methods or in additional methods.
// TODO: Wire up authentication (Windows/ASP.NET Forms) and uncomment the following to disable anonymous access
// Also consider adding roles to restrict access as appropriate.
// [RequiresAuthentication]
[EnableClientAccess()]
public class DomainService1 : LinqToEntitiesDomainService<MySamplerDBEntities>
{
// TODO:
// Consider constraining the results of your query method. If you need additional input you can
// add parameters to this method or create additional query methods with different names.
// To support paging you will need to add ordering to the 'Customers' query.
public IQueryable<Customer> GetCustomers()
{
return this.ObjectContext.Customers;
}
public void InsertCustomer(Customer customer)
{
if ((customer.EntityState != EntityState.Detached))
{
this.ObjectContext.ObjectStateManager.ChangeObjectState(customer, EntityState.Added);
}
else
{
this.ObjectContext.Customers.AddObject(customer);
}
}
public void UpdateCustomer(Customer currentCustomer)
{
this.ObjectContext.Customers.AttachAsModified(currentCustomer, this.ChangeSet.GetOriginal(currentCustomer));
}
public void DeleteCustomer(Customer customer)
{
if ((customer.EntityState == EntityState.Detached))
{
this.ObjectContext.Customers.Attach(customer);
}
this.ObjectContext.Customers.DeleteObject(customer);
}
// TODO:
// Consider constraining the results of your query method. If you need additional input you can
// add parameters to this method or create additional query methods with different names.
// To support paging you will need to add ordering to the 'Towns' query.
public IQueryable<Town> GetTowns()
{
return this.ObjectContext.Towns;
}
public void InsertTown(Town town)
{
if ((town.EntityState != EntityState.Detached))
{
this.ObjectContext.ObjectStateManager.ChangeObjectState(town, EntityState.Added);
}
else
{
this.ObjectContext.Towns.AddObject(town);
}
}
public void UpdateTown(Town currentTown)
{
this.ObjectContext.Towns.AttachAsModified(currentTown, this.ChangeSet.GetOriginal(currentTown));
}
public void DeleteTown(Town town)
{
if ((town.EntityState == EntityState.Detached))
{
this.ObjectContext.Towns.Attach(town);
}
this.ObjectContext.Towns.DeleteObject(town);
}
}
}
Для того, чтобы отобразить данные в окне Silverlight приложения нужно просто перетащить нужные данные из окна Data Sources на форму в виде, например, грида.
Вот таким будем код стараницы Main если на нее перетащить такой грид:
<UserControl
x:Class="BusinessApplication1.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:navigation="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Navigation"
xmlns:uriMapper="clr-namespace:System.Windows.Navigation;assembly=System.Windows.Controls.Navigation"
xmlns:dataControls="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data.DataForm.Toolkit"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" d:DesignWidth="640" d:DesignHeight="480" xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk" xmlns:riaControls="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.DomainServices" xmlns:my="clr-namespace:BusinessApplication1.Web.Services" xmlns:my1="clr-namespace:BusinessApplication.BLL">
<Grid x:Name="LayoutRoot" Style="{StaticResource LayoutRootGridStyle}">
<Border x:Name="ContentBorder" Style="{StaticResource ContentBorderStyle}">
<navigation:Frame x:Name="ContentFrame" Style="{StaticResource ContentFrameStyle}"
Source="/Home" Navigated="ContentFrame_Navigated" NavigationFailed="ContentFrame_NavigationFailed">
<navigation:Frame.UriMapper>
<uriMapper:UriMapper>
<uriMapper:UriMapping Uri="" MappedUri="/Views/Home.xaml"/>
<uriMapper:UriMapping Uri="/{pageName}" MappedUri="/Views/{pageName}.xaml"/>
</uriMapper:UriMapper>
</navigation:Frame.UriMapper>
</navigation:Frame>
</Border>
<Grid Style="{StaticResource NavigationOuterGridStyle}">
<Grid x:Name="NavigationGrid" Style="{StaticResource NavigationGridStyle}">
<Border x:Name="BrandingBorder" Style="{StaticResource BrandingBorderStyle}">
<StackPanel x:Name="BrandingStackPanel" Style="{StaticResource BrandingStackPanelStyle}">
<ContentControl Style="{StaticResource LogoIcon}"/>
<TextBlock x:Name="ApplicationNameTextBlock" Style="{StaticResource ApplicationNameStyle}"
Text="{Binding ApplicationStrings.ApplicationName, Source={StaticResource ResourceWrapper}}"/>
</StackPanel>
</Border>
<Border x:Name="LinksBorder" Style="{StaticResource LinksBorderStyle}">
<StackPanel x:Name="LinksStackPanel" Style="{StaticResource LinksStackPanelStyle}">
<HyperlinkButton x:Name="Link1" Style="{StaticResource LinkStyle}"
NavigateUri="/Home" TargetName="ContentFrame" Content="{Binding Path=ApplicationStrings.HomePageTitle, Source={StaticResource ResourceWrapper}}"/>
<Rectangle x:Name="Divider1" Style="{StaticResource DividerStyle}"/>
<HyperlinkButton x:Name="Link2" Style="{StaticResource LinkStyle}"
NavigateUri="/About" TargetName="ContentFrame" Content="{Binding Path=ApplicationStrings.AboutPageTitle, Source={StaticResource ResourceWrapper}}"/>
</StackPanel>
</Border>
</Grid>
<Border x:Name="loginContainer" Style="{StaticResource LoginContainerStyle}">
<!-- LoginStatus will be added here in code behind. This is required for the designer view to work -->
</Border>
<sdk:DataGrid AutoGenerateColumns="False" Height="200" HorizontalAlignment="Left" ItemsSource="{Binding ElementName=customerDomainDataSource, Path=Data}" Margin="100,123,0,0" Name="customerDataGrid" RowDetailsVisibilityMode="VisibleWhenSelected" VerticalAlignment="Top" Width="400">
<sdk:DataGrid.Columns>
<sdk:DataGridTextColumn x:Name="iDColumn" Binding="{Binding Path=ID, Mode=OneWay}" Header="ID" IsReadOnly="True" Width="SizeToHeader" />
<sdk:DataGridTextColumn x:Name="nameColumn" Binding="{Binding Path=Name}" Header="Name" Width="SizeToHeader" />
<sdk:DataGridTextColumn x:Name="townIDColumn" Binding="{Binding Path=TownID}" Header="Town ID" Width="SizeToHeader" />
</sdk:DataGrid.Columns>
</sdk:DataGrid>
</Grid>
<riaControls:DomainDataSource AutoLoad="True" d:DesignData="{d:DesignInstance my1:Customer, CreateList=true}" Height="0" LoadedData="customerDomainDataSource_LoadedData" Name="customerDomainDataSource" QueryName="GetCustomersQuery" Width="0">
<riaControls:DomainDataSource.DomainContext>
<my:DomainService1 />
</riaControls:DomainDataSource.DomainContext>
</riaControls:DomainDataSource>
</Grid>
</UserControl>
Комментариев нет:
Отправить комментарий