65.9K
CodeProject 正在变化。 阅读更多。
Home

四个简单步骤:使用 DevForce 创建 Silverlight 业务应用程序

emptyStarIconemptyStarIconemptyStarIconemptyStarIconemptyStarIcon

0/5 (0投票)

2009年3月25日

CPOL

13分钟阅读

viewsIcon

26628

使用 IdeaBlade DevForce Silverlight 创建 Silverlight 应用程序

DevForce 从一开始就由经验丰富的企业应用程序开发者设计,并牢记几个非常重要的目标

  • “尽可能地简单,但不要过于简单。”(遵循阿尔伯特·爱因斯坦的著名建议)。
  • 支持(并鼓励)架构中的“关注点分离”:您的业务模型(以及所有业务逻辑)与用户界面完全分开,因此您可以跨多个用户界面和多个应用程序重用它。
  • “不要限制我。” 您可以构建您想要的应用程序,具有您所需的功能和用户界面。我们让这一切变得更容易,并确保您的最终产品真正具备工业级强度——但我们不会主导,也不会阻碍您。开始时不会,而且——更重要的是——之后也不会,当您投入了大量开发精力,以至于改变方向不再是可选项时。

    那么,使用 DevForce Silverlight 构建应用程序是什么样的呢?让我们一步步来看看这四个简单的步骤

  • 使用 DevForce Silverlight 项目模板生成您的 Silverlight 和 Web 项目
  • 创建您的实体数据模型
  • 创建您的 DevForce 域模型
  • 创建您的 UI。

下载 DevForce

第一步:生成您的 Silverlight 和 Web 项目

DevForce 提供了一个 Visual Studio 项目模板,可以快速启动您的应用程序。从主菜单中选择“文件”/“新建”/“项目”,在您选择的语言下找到 DevForce 部分,然后选择“DevForce Silverlight 应用程序”项目模板。

指定新解决方案的名称和存储位置,然后单击“确定”

该模板创建了两个项目。Web 项目(此处名为 DevForceSilverlightAppWeb)最终将部署在您的 IIS 服务器上;Silverlight 项目(DevForceSilverlightApp)将包含应用程序部分,这些部分将通过 .XAP 文件自动下载到客户端浏览器。

请注意,Web 项目被设置为解决方案的启动项目。这很重要!如果将 Silverlight 应用设置为启动项目,主页仍然会显示,但所有需要连接到服务器的操作——例如登录和数据检索——都将无法进行!

第一步就到这里。我们有了应用程序结构,并且需要的 DevForce 和 .NET 程序集的引用已经设置好了。让我们继续创建应用程序的业务模型!

第二步:创建您的实体数据模型

ADO.NET 实体数据模型仅在我们的 DevForce Silverlight 应用程序的服务器端使用,因此让我们将其添加到 Web 项目中

请注意,将实体数据模型添加到 Web 项目并非您唯一的选择:您也可以选择为其创建一个单独的项目。唯一的要求是它最终应该驻留在已部署到服务器端的程序集中。

下载 DevForce

我们将对其命名以指示其在应用程序中的功能以及它将映射到的数据库

我们将从数据库生成应用程序……

……命名我们的连接设置……

……选择我们要映射的表……

……然后单击“完成”。向导生成了实体数据模型,如下所示

EDM 向导生成的模型存在一些命名问题。首先,无法区分返回集合的导航属性和返回单个相关对象的导航属性。出现在 Customer 和 Employee 实体上的 Order 属性在每种情况下都返回一个 Order 集合。OrderDetail 在 Order 类型中也是如此。但是 Order 类型中的 Customer 和 Employee 返回的是单个对象,而不是集合。如果名称的复数形式能反映属性的实际内容,那会很有帮助。

此外,如果我们检查模型中定义的任何实体的属性,我们会看到保存该实体实例的 Entity Set 的名称与类型本身的名称相同:同样,这不太有用,因为我们可能希望 Set 名称是复数形式,而类型名称是单数形式。

我们可以使用 EDM 设计器来清理这些问题,但碰巧的是,在 DevForce 对象映射器中这样做要容易得多,所以我们将推迟清理,直接进行第三步。

第三步:创建您的 DevForce 域模型

现在我们有了实体数据模型,我们可以创建 DevForce 生成的域模型了。不过,在此之前,让我们花几分钟回答几个基本问题

  • 为什么要有两个模型?以及
  • 在 DevForce Silverlight 应用中,我能得到什么而其他任何 Silverlight 应用都得不到?

Microsoft 提供的 ADO.NET 实体数据模型为将对象映射到关系数据库提供了出色的结构,并且通过 Microsoft 实体框架的使用,允许您(开发人员)完全卸载编写数据访问代码的工作。您不仅不再需要掌握不同 DBMS 供应商支持的各种 SQL 方言:您也不再需要以任何形式编写 SQL。在应用程序代码中,您与一个可以完美匹配您应用程序的对象模型进行交互。您被缓冲在后端数据库的设计细节之外,后端数据库可能与您的应用程序不匹配,并且难以或不可能更改。

不幸的是,实体数据模型不能在 Silverlight 应用程序中使用,因为 Silverlight 中没有任何东西知道如何对其进行任何有用的操作。(实体框架不是 Silverlight 的一部分。)

真糟糕!

但是等等…… DevForce 来拯救你了!

DevForce 利用应用程序服务器上实体数据模型和实体框架的功能和优势,但为您提供了一个模型和围绕它的设备,这些模型和设备可以在您的 Silverlight 客户端中以非常强大的方式使用。DevForce 包含一个 EntityManager,其功能类似于实体框架的 ObjectContext,但功能更强大。这个 EntityManager 驻留在客户端,并维护一个业务对象缓存,您可以使用 LINQ 查询它!

但是 DevForce 生成的 DomainModel 也将在服务器端使用。DevForce 以适合两种不同环境的方式在服务器端和客户端使用该模型。您只需要维护一个业务模型——而不是两个。

下图显示了 DevForce 如何使您能够在 Silverlight 应用程序中利用实体框架的强大功能。Devforce EntityManager 维护着一个可查询的客户端缓存,其中包含从后端数据存储中检索到的业务对象。

DevForce 启用的 LINQ 查询可以针对客户端缓存后端数据存储

当针对数据存储执行查询时,它们会被 DevForce Entity Server 自动转换为实体框架可以处理的 LINQ-to-Entities 查询。然后,实体框架生成必要的 SQL 以从数据库中检索数据,并将其传递给 DevForce Entity Server。Entity Server 非常高效地将数据发送到客户端,在那里将其转换为您的 DevForce Domain Model 中定义的类型的 DevForce 业务对象。

Crossflow of Data and Business Objects.png

顺便说一句,与实体数据模型不同,DevForce Domain Model 不限制您只使用单个数据库作为数据源。DevForce Domain Model 可以包含任意数量的实体数据模型,每个模型映射到一个不同的关系数据库。更进一步,它可以利用 DevForce 生成的基于Web 服务的实体数据模型——这是标准实体数据模型完全无法实现的!

我们的实体数据模型将从 DevForce 获得一些自动修改,但其余的将保持原样。其目的是将您编写所有应用程序代码的 DomainModel 与 Microsoft 实体框架强大的数据检索和存储功能链接起来。

好了,背景介绍结束。让我们来看看创建 DevForce DomainModel 有多容易。

首先,从 Visual Studio 的“工具”菜单启动 DevForce Object Mapper

Object Mapper 启动。通过下拉“模型”菜单或右键单击左面板中的(新建模型)节点,我们可以开始将域模型链接到现有实体数据模型的过程

由于我们的解决方案中只有一个实体数据模型,Object Mapper 会自动找到它。您只需单击“打开”按钮确认这是您想包含在域模型中的实体数据模型。

Object Mapper 将快速挖掘 EDM 以获取信息,然后显示其结构。

下载 DevForce

通过选择树中的 ServerModelNorthwindIBContext 节点,您可以查看(并编辑)EDM 的更多详细信息。

我们将深入研究 Order 类型,并将 Freight 属性(基于 NorthwindIB 数据库中 Order 表中的 Freight 列)的名称更改为 FreightCost。

同样,我们将导航属性 Employee 的名称更改为“SalesRep”,以反映 Employee 相对于 Order 的实际角色

Employee 类型上的导航属性 Employee1 和 Employee2 是由 EDM 向导在 Employee 表上发现自引用关系后生成的。该关系反映了 Employee 之间的递归层次结构:任何 Employee 都向一位经理汇报,但可以成为许多其他 Employee 的经理。EDM 向导尽了最大努力命名所需的导航属性……

……但我们真的想做得更好。问题是,我们很难分辨哪个导航属性将返回当前 Employee 的唯一经理,哪个将返回她直接下属的集合。

我们的模型中还有其他令人讨厌的小命名问题。如果您重新检查早期屏幕截图中的一个,您可以看到实体集被命名为与实体类型相同的名称

我们真的想区分 Set 名称和它们包含的类型的名称。我们可以逐个进行,但 Object Mapper 有一个方便的小工具,可以一劳永逸地解决我们所有与复数相关的命名问题:位于 .edmx 节点详细信息屏幕上的 Name Pluralizer

我们将接受默认设置并单击“确定”。

实体集现在有了复数名称……

……返回集合的导航属性也是如此。

现在很容易看出如何更改我们关于管理层级的导航属性了

=>

我们可以在 Object Mapper 中更改许多其他设置,但让我们假设我们认为已经完成了足够多的工作,可以生成模型代码并开始处理开发过程的其他方面。(我们始终可以回到 Object Mapper 进行进一步工作。)

我们选择模型树中的 Domain Model 节点

如果我们接受 Object Mapper 建议的默认位置,并指示我们希望通过标有“创建开发人员部分类文件”的复选框来“创建开发人员部分类文件”,那么最终的解决方案将如下所示

Object Mapper 生成了一个代码文件

DevForceSilverlightAppWeb.ServerModelNorthwindIB.Designer.cs

到 Web 项目中,以及域模型中每种类型(Customer、Employee、Order 等)的代码文件。它还将相同代码文件的链接副本放入 Silverlight 项目中,以便相同的代码将被编译到从该项目中创建的 Silverlight 程序集中。

您可以在 Object Mapper 中做更多的事情:定义和分配基类、允许或禁止空值、强制执行字符串的列宽、设置用于诊断并发冲突的设施等等。但您的模型不必比您需要的更复杂,并且您可以逐步引入细节。Object Mapper 支持双向修改,因此您可以在整个应用程序开发周期中返回它来添加、删除或修改您的对象。

您几乎肯定想在开发人员部分类(位于 Customer.cs、Employee.cs 和 Order.cs 文件中)中添加自定义业务逻辑,包括自定义属性和方法、属性拦截器、验证逻辑(使用 DevForce 非常强大的 Verification 功能)、安全逻辑、事件处理程序等。但现在我们的模型已准备好进行复杂的数据检索和存储,所以让我们添加一个 UI,然后让它运行起来。

下载 DevForce

第四步:在配置好的 Silverlight 项目中创建您的用户界面

实际上,我们已经有了一个 UI。我们的 Silverlight 项目生成了一个 XAML MainPage(以及相关的“代码隐藏”文件),它被设置为应用程序的启动页。实际上,我们可以立即运行应用程序。如果我们这样做,我们会看到这个

看到我们的应用程序已经可以运行,这让人感到欣慰,但让我们来构建一个利用那些强大的数据持久性功能的东西!我们将向 MainForm 添加一个 TabControl(只是为了创建未来的扩展可能性),并给它一个 TabItem。在这个 TabItem 中,我们将添加一个自定义 UserControl,名为 DynamicGridEditor。

当我们运行应用程序时,它看起来像这样

DynamicGridEditor 使用 Silverlight 3 DataGrid 显示一个由最终用户从标记为“Query:”的 ComboBox 中选择的查询满足的实体列表。所选网格项的详细信息显示在 Silverlight 3 DataForm 中。Query ComboBox 实际上允许您选择返回不同类型的查询

这一切都用很少的代码完成!如果您下载了本文所基于的 Visual Studio 解决方案,您会发现添加返回其他类型的额外查询只需编写查询并将其放入 DynamicGridEditor 的“代码隐藏”中定义的字典即可。DataGrid 和 DataForm 会自动适应!

这是 MainForm 的完整 XAML

<UserControl x:Class="DevForceSilverlightApp.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:slControls=
        "clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls"
    xmlns:local="clr-namespace:DevForceSilverlightApp" 
    Width="Auto" Height="Auto">
    <Grid x:Name="LayoutRoot" Background="White" >
        <slControls:TabControl x:Name="_mainTabControl">
            <slControls:TabItem x:Name="_dynamicGridEditorTab"
                Header="Dynamic Grid Editor">
                <local:DynamicGridEditor />
            </slControls:TabItem>
        </slControls:TabControl>
    </Grid>
</UserControl>

这就是 DynamicGridEditor 在设计器中的样子……

……这是它的 XAML 的核心部分

    <StackPanel Grid.Row="0" Orientation="Horizontal" Margin="10,10" >
      <Button x:Name="_loginButton" Click="LoginButton_Click" 
         Style="{StaticResource button}" Content="Login" />
      <Button x:Name="_saveButton" Click="SaveButton_Click" 
         Style="{StaticResource button}" Content="Save" />
    </StackPanel>

    <StackPanel Grid.Row="1" Orientation="Horizontal" Margin="10,0" >
      <TextBlock>Query:</TextBlock>
      <ComboBox x:Name="_queryCombo" Margin="6,0" MinWidth="30"/>
      <TextBlock Margin="20,0,6,0" x:Name="_queryAsString" Foreground="Blue" />
    </StackPanel>

    <dataControls:DataGrid x:Name="_dataGrid" Grid.Row="2" 
      Margin="10,10" Style="{StaticResource grid}" 
      AutoGenerateColumns="True" HeadersVisibility="Column"
      SelectionChanged="DataGrid_SelectionChanged"
    />

    <Border Grid.Row="3" BorderThickness="1" Margin="10,0" BorderBrush="Gray">
      <dataformControls:DataForm x:Name="_dataForm"  Grid.Row="3" 
         Margin="10,10" CanUserAddItems="False" CanUserDeleteItems="False" 
         AutoGenerateFields="True" />
    </Border>

请注意 DataGrid 和 DataForm 控件中的 AutoGenerateColumns 和 AutoGenerateFields 设置。当与我们之前指示 Object Mapper“生成绑定属性”结合使用时……

……这些设置会导致控件选择正确的属性集来显示!

MainPage 中没有自定义“代码隐藏”,而 DynamicGridEditor 中的代码量也出奇地少。这是定义查询并初始化 Query ComboBox 的代码

    #region InitializeQueries

    private void InitializeQueries() {
      _queries = new Dictionary<string, EntityQuery>();

      _queries.Add("{None}", null);

      _queries.Add("Get all Customers", _entityManager.Customers);

      _queries.Add("Get Customers starting with 'A'",
                  _entityManager.Customers
                    .Where(c => c.CompanyName.StartsWith("A")));

      …[snip]…

      InitializeQueryCombo();
    }

    private void InitializeQueryCombo() {
      var qNames = _queries.Keys.ToList();
      _queryCombo.ItemsSource = qNames;
      _queryCombo.SelectedItem = qNames.FirstOrDefault();
      _queryCombo.SelectionChanged += delegate { Fetch(); };
    }

    #endregion

当选定的查询执行时,其结果将简单地放入一个列表,然后该列表被分配给 DataGrid 的 ItemsSource 属性。最后,DataForm 的 ItemsSource 被设置为 DataGrid 的 ItemSource。这确保了两个控件中显示的数据将同步。

为了看到更多内容,我们鼓励您下载本文所基于的 Visual Studio 解决方案并进行试用。您将对这个小巧、快速构建的解决方案中的强大功能感到惊讶!

下载 DevForce

结论

就这样:四个简单的步骤,构建了一个 N 层 Silverlight 应用程序。有了 DevForce 和 Silverlight,您现在就可以构建数据密集型的富互联网应用程序,提供出色的用户体验和无缝的部署。通过让您摆脱编写和维护支持 N 层模型所需的广泛管道和基础结构代码的任务,DevForce 使您能够专注于构建您和您的客户所需和想要的应用程序。

DevForce 随附大量文档、代码示例和教程,可帮助您处理各种开发任务;世界一流的工程师团队将在您遇到困难时提供帮助。今天就来试试吧!

© . All rights reserved.