AdventureWorks.WPF (第一部分)






3.77/5 (22投票s)
我创建实际业务应用程序的旅程
背景
WPF 准备好应对真实世界的挑战了吗?答案是肯定的!那么,证明它吧!
接下来的几篇文章将是我使用 WPF 编写一个真实商业应用程序的文档记录!需要注意的是,我只使用了 WPF 提供的功能,而没有其他任何东西!!!第一部分将为未来的文章奠定基础。
为什么要写这篇文章,难道已经讲过了吗?
可能吧,但有什么比动手玩耍更好的学习方式呢?更严肃地说,我看到的唯一一个真正的参考应用程序是 DinnerNow 应用程序。 DinnerNow 是一个完美利用 .NET 3.0 所有功能的示例,但它有点过于复杂。这些文章的目的是介绍一些可以用来创建类似 DinnerNow 的应用程序的基础知识!!!
免责声明
这是一篇入门文章,但它假设您对 WPF、SQL Server、MVC 和 LINQ 有一定的了解。
WPF 简介
- WPF:入门指南 - 第 1 部分 (共 n 部分)
- WPF:入门指南 - 第 2 部分 (共 n 部分)
- WPF:入门指南 - 第 3 部分 (共 n 部分)
- WPF:入门指南 - 第 4 部分 (共 n 部分)
- WPF:初学者指南 - 第 5 部分(共 n 部分)
- WPF:入门指南 - 第 6 部分
- WPF 导览 - 第一部分 (XAML)
- WPF 导览 - 第二部分 (布局)
- WPF 导览 - 第 3 部分 (数据绑定)
- WPF 导览 - 第 4 部分 (数据模板和触发器)
- WPF 导览 - 第五部分 (样式)
高级 WPF
- WPF 业务应用程序系列 第 1 部分 (共 n 部分) - 应用程序结构、皮肤化和自定义工具栏 B
- WPF 业务应用程序系列 第 2 部分 (共 n 部分) - 绑定到 IDataError 的表单通知控件
- WPF 业务应用程序系列 第 3 部分 (共 n 部分)
- WPF Podcatcher 系列 - 第 1 部分 (Introducing Podder)
- WPF Podcatcher 系列 - 第 2 部分 (Structural Skinning)
- WPF Podcatcher 系列 – 第 3 部分 (The Podcast Management Conundrum)
MVC
- 使用 MVC 对 WPF 应用程序进行单元测试
- 你好,真实世界!
LINQ/SQL Server
- 第 1 部分 - LINQ to SQL 简介
- 第 2 部分 - 定义我们的数据模型类
- 第 3 部分 - 查询我们的数据库
- 第 4 部分 - 更新我们的数据库
- 第 5 部分 - 使用 ASP-LinqDataSource 控件绑定 UI
- 第 6 部分 - 使用存储过程检索数据
- 第 7 部分 - 使用存储过程更新我们的数据库
- 第 8 部分 - 执行自定义 SQL 表达式
- 第 9 部分 - 将自定义 LINQ 表达式与 <asp:LinqDatasource> 控件结合使用
WPF 训练营
- WPF 训练营 2007
- WPF 训练营 2008
大多数 LOB 应用程序都消耗和操作数据... 因此,让我们从那里开始!
开始之前...
好的,这很明显,但请使用 Visual Studio 2008 创建一个新的 WPF 应用程序项目!
Data
可以安全地假设 Microsoft SQL Server 是一个流行的数据源。下载 AdventureworksLT SQL 数据库并进行安装。
创建 LINQ-to-SQL 映射
向项目添加一个新项,使用“LINQ to SQL Classes”模板。
打开服务器资源管理器并添加一个数据连接。输入您的服务器名称,然后选择 AdventureWorksLT
作为数据库。
添加后,选择所有表并将它们拖到设计表面。这将创建所有必需的实体(我们的模型)。
模型-视图-控制器?
我将松散地遵循 Josh 对 MVC 模式的实现,我的可能更像 Dr. WPF 的 MV-poo。
模型
应用程序运行所依赖的信息的特定领域表示。
免责声明
我不是软件架构师,本文也不是关于如何构建 nTier 或 MVC 应用程序的设计指南。
虽然这是我追求创建真实 LOB 应用程序的历程... 但目前,我将稍微作弊一下。我将使用 LINQ 返回的数据集作为我的模型。这种方法的好处是它已经实现了 INotifyPropertyChanged
事件!在所有真正的架构师开始抨击我之前,未来的文章将解决这个问题。
为了不过多透露,未来的计划是拥有一个 SQL DB -> LINQ-to-SQL -> WCF 服务 -> 模型。
模型的主要目的是以易于绑定的格式表示数据!
关于代码
如果您运行提供的示例代码,请记住更改设置文件中的连接字符串。它目前使用此连接字符串
Data Source=
localhost\sqlexpress;Initial Catalog=AdventureWorksLT;Integrated Security=True
视图
将模型渲染成适合交互的形式。这正是 WPF 发挥作用的地方... 我正在创建各种用户控件并将它们绑定到我的窗口内容!
视图和模型之间的通信通过数据绑定和路由命令(通过控制器)进行。
每个视图都将加载到一个新窗口中。我将使用 这些 附加属性来跟踪我打开的窗口。
local:WindowViewState.IsManaged="True"
销售订单

好了,我没有 Grant Hinkson 在我的口袋里... 它不漂亮,但它很实用!!!
此视图的目的是允许用户查看/编辑任何现有销售订单。订单日期、截止日期、发货日期、发货方式等数据都可以更改。要更改客户详细信息,将使用一个单独的视图。每个客户都有一个关联的地址列表,收货地址和账单地址只能更改为列表中已有的有效地址。
还将支持以下命令:新建、删除和更新(将在后续文章中实现)。
销售订单视图数据绑定到 SalesOrderHeaders
集合。
Customers

此视图用于查看/编辑客户。姓名、中间名、姓氏等详细信息都可以更改。
客户视图数据绑定到 Customers
集合。
产品

此视图用于查看/编辑产品。名称、零件号、标价等详细信息都可以更改。
产品视图数据绑定到 Products
集合。
控制器 (又名 Poo)
处理响应事件,通常是用户操作,并可能对模型进行更改。控制器基本上是将模型和视图粘合在一起的胶水。
控制器用于与模型交互(例如,添加新销售订单、删除销售订单、更新销售订单)。
我为视图可以执行的每个操作创建了一些路由命令。有关路由命令的更多信息,请阅读 Josh Smith 发表的 这篇文章。
绑定问题 1 (共 n 部分)
本文主要关注数据绑定。在我们深入之前,请阅读 这篇文章,了解我学到的关于绑定的知识... 这些文章将大量使用它!!!
绑定到规范化数据库
以 AdventureWorksLT
为例。每个客户都有一个地址列表。每个销售订单都有一个客户。如果我现在想创建一个销售订单的数据录入屏幕,我该如何正确绑定它,以便我可以更改交货/账单地址,但仍然将我的选项限制在可用地址内?
<ComboBox ItemsSource="
{Binding Path=Customer.CustomerAddresses, Mode=TwoWay, UpdateSourceTrigger=Explicit}"
SelectedValue="{Binding Path=ShipToAddressID}" SelectedValuePath="AddressID" />
ComboBox
非常适合此场景,我首先将 ComboBox.ItemsSource
绑定到所有可用地址(由 Customer
限制)。现在需要做的就是告诉 ComboBox
当前应该选择哪个项目。SelectedValuePath
确定应该使用哪个属性来“标识”当前项目,然后将 SelectedValue
绑定...
仔细检查... ComboBox
绑定到 Customer.CustomerAddresses
,但 SelectedValue
实际上使用的是视觉树上方的绑定源!
这是规范化数据库中一个非常常见的场景...
BindingMode.TwoWay
默认绑定模式并非所有控件都相同。显式设置绑定模式始终是安全的做法。在此场景中,我们将大部分时间使用 BindingMode.TwoWay
。我们希望绑定自动更新我们的模型!
Mode=TwoWay
主/明细绑定
一个常见的场景是主/明细绑定... 如果以销售订单为例... 我将一个 ComboBox
绑定到一系列未关闭的销售订单(Master
),一旦选择了销售订单,其详细信息将在详细信息窗格(Detail
)中显示。
有两种常见的方法可以做到这一点
将详细信息窗格的 DataContext
绑定到 ComboBox.SelectedItem
DataContext="{Binding Path=SelectedItem, ElementName=SalesOrdersListBox}"
或者使用 {Binding Path=/}
语法。
要使用此绑定,首先设置 IsSynchronizedWithCurrentItem="True"
,然后像这样绑定 DataContext
DataContext="{Binding Path=/}"
UpdateSourceTrigger.Explicit
我想控制数据源何时更新。稍后将详细介绍。
UpdateSourceTrigger=Explicit
WPF 缺少什么(目前)
我确定当时时间是唯一的限制,但 WPF 急需两个控件才能进入 LOB 市场...
日期选择器
这里我使用了 Marlon 的 AvalonControlsLibrary。(它是免费的,并且提供了完整的源代码。)
DataGrid
目前我只使用了一个 ListView
,但很快我将升级到 Xceed DataGrid。(它是免费的。)
未来将要解决的问题
- 控制器和路由命令(提供新建、删除和更新)
- 验证
- 迁移到数据服务模型并跨越机器边界
第一部分就到这里了... 如果您觉得这有帮助,请为您喜欢的文章投票... 任何评论(好坏皆可)都非常欢迎!