пятница, 27 августа 2010 г.

Использование Silverlight 4. Часть 3

В этот раз попробуем добавить в приложение какую-нибудь логику и добавить отображение данных.

Обычно я создаю дополнительный проект для слоя бизнес логики, а работа с базой данных осуществляется с помощью Entity Framework.

То есть поступаем так:

Создаем новый Windows Class Library проект BusinessApplication.BLL.

В него добавляетм ADO.NET Entity Data Model.

clip_image002

Не забываем выбрать галочку Pluralize or singularize generated object names.

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

clip_image004

Теперь нам нужно сделать сервис, который будет отдавать Silverlight приложению данные. В папке Services ASP.NET проекта добавляем новый элемент Domain Service Class (перед этим не забываем добавить BLL проект в списко зависимостей Web проекта, и скоспилировать все это вместе).

clip_image006

clip_image008

В мастере выбираем все сущности, ставим галочку на Enable client access. Уже сейчас нас поджидает первая неожиданность:

Мы не можем поставить галочку на Generate associated classes for metadata. Дело в том, что модель данных содержится в другом проекте и, почему-то из-за этого нельзя создать файл с метаданными…

К счастью есть простое решение этой проблемы:

Создаем Domain Service Class с таким же названием в BLL проекте

Для него ставим галочку Generate associated classes for metadata

clip_image010

После этого появятся два файла.

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>

Комментариев нет:

Отправить комментарий