使用 WPF 和 Entity Framework 6 创建简单的数据应用程序Create a simple data application with WPF and Entity Framework 6

08/22/2017

本文内容

本演练演示如何在 Visual Studio 中创建基本的 "窗体 over 数据" 应用程序。This walkthrough shows how to create a basic "forms over data" application in Visual Studio. 应用使用 SQL Server LocalDB、Northwind 数据库、实体框架 6 (不 Entity Framework Core) 和 Windows Presentation Foundation .NET Framework (.NET Core) 。The app uses SQL Server LocalDB, the Northwind database, Entity Framework 6 (not Entity Framework Core), and Windows Presentation Foundation for .NET Framework (not .NET Core). 它演示了如何使用大纲-详细信息视图进行基本数据绑定,还提供了一个自定义绑定导航器,其中包含用于 移动 的按钮、" 上 移"、"移 至开头 "、" 结束 "、" 更新 " 和 " 删除 "。It shows how to do basic databinding with a master-detail view, and it also has a custom Binding Navigator with buttons for Move Next , Move Previous , Move to beginning , Move to end , Update and Delete.

本文重点介绍如何在 Visual Studio 中使用数据工具,并且不会尝试深入了解底层技术。This article focuses on using data tools in Visual Studio, and does not attempt to explain the underlying technologies in any depth. 假设您基本熟悉 XAML、实体框架和 SQL。It assumes that you have a basic familiarity with XAML, Entity Framework, and SQL. 此示例还不演示模型-视图-ViewModel (MVVM) 体系结构,这是 WPF 应用程序的标准。This example also does not demonstrate Model-View-ViewModel (MVVM) architecture, which is standard for WPF applications. 不过,你可以将此代码复制到你自己的 MVVM 应用程序中,只需修改少量内容。However, you can copy this code into your own MVVM application with few modifications.

安装并连接到 NorthwindInstall and connect to Northwind

此示例使用 SQL Server Express LocalDB 和 Northwind 示例数据库。This example uses SQL Server Express LocalDB and the Northwind sample database. 如果该产品的 ADO.NET 数据提供程序支持实体框架,则它也适用于其他 SQL 数据库产品。If the ADO.NET data provider for that product supports Entity Framework, it should work with other SQL database products just as well.

如果没有 SQL Server Express 的 LocalDB,请从 SQL Server Express 下载 "页或通过 Visual Studio 安装程序 安装它。If you don't have SQL Server Express LocalDB, install it either from the SQL Server Express download page, or through the Visual Studio Installer. 在 Visual Studio 安装程序中,可将 SQL Server Express LocalDB 作为 .NET 桌面开发工作负载的一部分安装,也可作为单独组件安装。In the Visual Studio Installer , you can install SQL Server Express LocalDB as part of the .NET desktop development workload or as an individual component.

按照以下步骤安装 Northwind 示例数据库:Install the Northwind sample database by following these steps:

在 Visual Studio 中,打开 " SQL Server 对象资源管理器 " 窗口。In Visual Studio, open the SQL Server Object Explorer window. ( SQL Server 对象资源管理器 在 Visual Studio 安装程序 的 数据存储和处理 工作负荷中安装。 ) 展开 SQL Server 节点。( SQL Server Object Explorer is installed as part of the Data storage and processing workload in the Visual Studio Installer.) Expand the SQL Server node. 右键单击 LocalDB 实例,然后选择 " 新建查询 "。Right-click on your LocalDB instance and select New Query.

此时将打开查询编辑器窗口。A query editor window opens.

此 T-sql 脚本从头开始创建 Northwind 数据库,并用数据填充它。This T-SQL script creates the Northwind database from scratch and populates it with data.

将 T-sql 脚本粘贴到查询编辑器中,然后选择 " 执行 " 按钮。Paste the T-SQL script into the query editor, and then choose the Execute button.

一小段时间后,查询将完成运行,并创建 Northwind 数据库。After a short time, the query finishes running and the Northwind database is created.

为 Northwind添加新连接。

配置项目Configure the project

在 Visual Studio 中,创建一个新的 c # WPF 应用程序 项目。In Visual Studio, create a new C# WPF App project.

为实体框架6添加 NuGet 包。Add the NuGet package for Entity Framework 6. 在 解决方案资源管理器 中,选择 "项目" 节点。In Solution Explorer , select the project node. 在主菜单中,选择 " 项目 " " > 管理 NuGet 包 "。In the main menu, choose Project > Manage NuGet Packages.

在 NuGet 包管理器 中,单击 " 浏览 " 链接。In the NuGet Package Manager , click on the Browse link. 实体框架可能是列表中的顶层包。Entity Framework is probably the top package in the list. 单击右窗格中的 " 安装 ",并按照提示进行操作。Click Install in the right pane and follow the prompts. "输出" 窗口将显示安装完成的时间。The Output window tells you when the install is finished.

现在,可以使用 Visual Studio 创建基于 Northwind 数据库的模型。Now you can use Visual Studio to create a model based on the Northwind database.

创建模型Create the model

右键单击 " 解决方案资源管理器 中的项目节点,然后选择" 添加 > 新项 "。Right-click on the project node in Solution Explorer and choose Add > New Item. 在左窗格中的 "c #" 节点下,选择 " 数据 ",然后在中间窗格中选择 " ADO.NET 实体数据模型 "。In the left pane, under the C# node, choose Data and in the middle pane, choose ADO.NET Entity Data Model.

调用模型 Northwind_model ,然后选择 "确定" 。Call the model Northwind_model and choose OK. 实体数据模型向导 将打开。The Entity Data Model Wizard opens. 从数据库中选择 EF 设计器 ,然后单击 " 下一步 "。Choose EF Designer from database and then click Next.

在下一个屏幕中,输入或选择 LocalDB Northwind 连接 (例如, (LocalDB) \MSSQLLocalDB) ,指定 Northwind 数据库,然后单击 " 下一步 "。In the next screen, enter or choose your LocalDB Northwind connection (for example, (localdb)\MSSQLLocalDB), specify the Northwind database, and click Next.

在向导的下一页上,选择要包含在实体框架模型中的表、存储过程和其他数据库对象。In the next page of the wizard, choose which tables, stored procedures, and other database objects to include in the Entity Framework model. 展开树视图中的 "dbo" 节点,然后选择 " 客户 "、" 订单 " 和 " 订单详细信息 "。Expand the dbo node in the tree view and choose Customers , Orders , and Order Details. 保留默认选中状态,并单击 " 完成 "。Leave the defaults checked and click Finish.

向导将生成表示实体框架模型的 c # 类。The wizard generates the C# classes that represent the Entity Framework model. 类是普通的旧 c # 类,并且是我们在 WPF 用户界面中进行 databind 的。The classes are plain old C# classes and they are what we databind to the WPF user interface. .Edmx 文件描述了关联类与数据库中的对象的其他元数据。The .edmx file describes the relationships and other metadata that associates the classes with objects in the database. Tt 文件是 T4 模板,用于生成对模型进行操作并将更改保存到数据库的代码。The .tt files are T4 templates that generate the code that operates on the model and saves changes to the database. 可以在 "Northwind_model" 节点下 解决方案资源管理器 查看所有这些文件:You can see all these files in Solution Explorer under the Northwind_model node:

.Edmx 文件的设计器图面使你可以修改模型中的某些属性和关系。The designer surface for the .edmx file enables you to modify some properties and relationships in the model. 在本演练中,我们不打算使用设计器。We are not going to use the designer in this walkthrough.

Tt 文件是常规用途,你需要调整其中一个文件以使用 WPF 数据绑定,这需要 ObservableCollections。The .tt files are general purpose and you need to tweak one of them to work with WPF databinding, which requires ObservableCollections. 在 解决方案资源管理器 中,展开 "Northwind_model" 节点,直到找到 " Northwind_model"。In Solution Explorer , expand the Northwind_model node until you find Northwind_model.tt. (确保你不在中 。Context.tt 文件,它位于 .edmx 文件的正下方。 )(Make sure you are not in the .Context.tt file, which is directly below the .edmx file.)

Replace the first occurrence of HashSet with ObservableCollection around line 51. 请勿替换第二次出现的 HashSet。Do not replace the second occurrence of HashSet.

按 Ctrl + Shift + B 生成项目。Press Ctrl+Shift+B to build the project. 当生成完成时,这些模型类对于 "数据源向导" 可见。When the build finishes, the model classes are visible to the data sources wizard.

现在您已准备好将此模型挂接到 XAML 页,以便您可以查看、导航和修改数据。Now you are ready to hook up this model to the XAML page so that you can view, navigate, and modify the data.

将模型 Databind 到 XAML 页Databind the model to the XAML page

可以编写自己的数据绑定代码,但使 Visual Studio 可以更轻松地为你执行此操作。It is possible to write your own databinding code, but it is much easier to let Visual Studio do it for you.

从主菜单中,选择 " 项目 > " " 添加新数据源 " 以打开 " 数据源配置向导 "。From the main menu, choose Project > Add new data source to bring up the Data Source Configuration Wizard. 选择 " 对象 ",因为您要绑定到模型类,而不是绑定到数据库:Choose Object because you are binding to the model classes, not to the database:

展开项目的节点,然后选择 " 客户 "。Expand the node for your project, and select Customer. 订单的 (源自动从 Customer 的 Orders 导航属性生成 )(Sources for Orders are automatically generated from the Orders navigation property in Customer.)

单击“完成”。Click Finish.

在代码视图中导航到 mainwindow.xaml 。Navigate to MainWindow.xaml in Code View. 出于本示例的目的,我们将保持 XAML 简单。We're keeping the XAML simple for the purposes of this example. 将 Mainwindow.xaml 的标题更改为更具描述性的名称,并将其高度和宽度增加为 600 x 800。Change the title of MainWindow to something more descriptive, and increase its Height and Width to 600 x 800 for now. 以后随时可以更改它。You can always change it later. 现在,将这三个行定义添加到主网格,一行用于导航按钮,一个用于客户的详细信息,一个用于显示其订单的网格:Now add these three row definitions to the main grid, one row for the navigation buttons, one for the customer's details, and one for the grid that shows their orders:

现在打开 mainwindow.xaml ,以便在设计器中查看它。Now open MainWindow.xaml so that you're viewing it in the designer. 这会导致 " 数据源 " 窗口在 " 工具箱 " 旁边的 Visual Studio 窗口边距中显示为一个选项。This causes the Data Sources window to appear as an option in the Visual Studio window margin next to the Toolbox. 单击该选项卡以打开窗口,或者按 Shift + Alt + D 或选择 " 查看 > 其他 Windows > 数据源 "。Click on the tab to open the window, or else press Shift+Alt+D or choose View > Other Windows > Data Sources. 我们会将 Customers 类中的每个属性都显示在单独的文本框中。We are going to display each property in the Customers class in its own individual text box. 首先,单击 " 客户 " 组合框中的箭头,然后选择 " 详细信息 "。First, click on the arrow in the Customers combo box and choose Details. 然后,将节点拖动到设计图面的中间部分,以便设计器知道您希望它进入中间行。Then, drag the node onto the middle part of the design surface so that the designer knows you want it to go in the middle row. 如果丢失,则可以在 XAML 中以后手动指定该行。If you misplace it, you can specify the row manually later in the XAML. 默认情况下,控件在网格元素中垂直放置,但此时,您可以在窗体上对其进行排列。By default, the controls are placed vertically in a grid element, but at this point, you can arrange them however you like on the form. 例如,将 " 名称 " 文本框放在地址上方时,可能有意义。For example, it might make sense to put the Name text box on top, above the address. 本文的示例应用程序将对字段重新排序,并将其重新排列为两列。The sample application for this article reorders the fields and rearranges them into two columns.

在 "代码" 视图中,现在可以看到 Grid 第1行中的新元素 (父网格的中间行) 。In the code view, you can now see a new Grid element in row 1 (the middle row) of the parent Grid. 父网格具有一个 DataContext 属性,该属性引用已添加到元素中的 CollectionViewSource Windows.Resources 。The parent Grid has a DataContext attribute that refers to a CollectionViewSource that's been added to the Windows.Resources element. 假设该数据上下文在第一个文本框绑定到 Address 时,该名称将映射到 Address CollectionViewSource 中当前对象的属性 Customer 。Given that data context, when the first text box binds to Address , that name is mapped to the Address property in the current Customer object in the CollectionViewSource.

当客户在窗口的上半部分可见时,您希望在下半部分查看其订单。When a customer is visible in the top half of the window, you want to see their orders in the bottom half. 在单个网格视图控件中显示订单。You show the orders in a single grid view control. 若要使主/从数据绑定按预期工作,请务必绑定到 Customers 类中的 Orders 属性,而不是绑定到单独的 "订单" 节点。For master-detail databinding to work as expected, it is important that you bind to the Orders property in the Customers class, not to the separate Orders node. 将 Customers 类的 Orders 属性拖到窗体的下半部分,以便设计器将其放在第2行:Drag the Orders property of the Customers class to the lower half of the form, so that the designer puts it in row 2:

Visual Studio 生成了将 UI 控件连接到模型中的事件的所有绑定代码。Visual Studio has generated all the binding code that connects the UI controls to events in the model. 若要查看某些数据,你只需编写一些代码来填充模型。All you need to do, in order to see some data, is to write some code to populate the model. 首先,导航到 MainWindow.xaml.cs ,并将数据成员添加到数据上下文的 mainwindow.xaml 类。First, navigate to MainWindow.xaml.cs and add a data member to the MainWindow class for the data context. 已为您生成的此对象的行为类似于跟踪模型中的更改和事件的控件。This object, which has been generated for you, acts something like a control that tracks changes and events in the model. 你还将为客户和订单添加 CollectionViewSource 数据成员和关联的构造函数初始化逻辑。You'll also add CollectionViewSource data members for customers and orders, and the associated constructor initialization logic. 类的顶部应如下所示:The top of the class should look like this:

public partial class MainWindow : Window

{

NorthwindEntities context = new NorthwindEntities();

CollectionViewSource custViewSource;

CollectionViewSource ordViewSource;

public MainWindow()

{

InitializeComponent();

custViewSource = ((CollectionViewSource)(FindResource("customerViewSource")));

ordViewSource = ((CollectionViewSource)(FindResource("customerOrdersViewSource")));

DataContext = this;

}

为 system.string 添加 using 指令以将负载扩展方法添加到作用域中:Add a using directive for System.Data.Entity to bring the Load extension method into scope:

using System.Data.Entity;

现在,向下滚动并找到 Window_Loaded 事件处理程序。Now, scroll down and find the Window_Loaded event handler. 请注意,Visual Studio 已添加 CollectionViewSource 对象。Notice that Visual Studio has added a CollectionViewSource object. 这表示创建模型时选择的 NorthwindEntities 对象。This represents the NorthwindEntities object that you selected when you created the model. 您已经添加了该程序,因此您不需要这样做。You added that already, so you don't need it here. 让我们替换中的代码, Window_Loaded 使方法现在如下所示:Let's replace the code in Window_Loaded so that the method now looks like this:

private void Window_Loaded(object sender, RoutedEventArgs e)

{

// Load is an extension method on IQueryable,

// defined in the System.Data.Entity namespace.

// This method enumerates the results of the query,

// similar to ToList but without creating a list.

// When used with Linq to Entities, this method

// creates entity objects and adds them to the context.

context.Customers.Load();

// After the data is loaded, call the DbSet.Local property

// to use the DbSet as a binding source.

custViewSource.Source = context.Customers.Local;

}

按 F5 。Press F5. 应会看到检索到 CollectionViewSource 中的第一个客户的详细信息。You should see the details for the first customer that was retrieved into the CollectionViewSource. 还应在数据网格中看到它们的顺序。You should also see their orders in the data grid. 格式设置不是很好,因此让我们来解决这个问题。The formatting isn't great, so let's fix that up. 您还可以创建一种方法来查看其他记录并执行基本的 CRUD 操作。You can also create a way to view the other records and do basic CRUD operations.

调整页面设计并为新客户和订单添加网格Adjust the page design and add grids for new customers and orders

Visual Studio 生成的默认布局并非适用于你的应用程序,因此我们将在此处提供最终 XAML 以复制到你的代码中。The default arrangement produced by Visual Studio is not ideal for your application, so we'll provide the final XAML here to copy into your code. 还需要一些 "表单" (,它们实际上是网格) ,以使用户能够添加新客户或订单。You also need some "forms" (which are actually Grids) to enable the user to add a new customer or order. 为了能够添加新的客户和订单,您需要一组不是数据绑定到的单独的文本框 CollectionViewSource 。In order to be able to add a new customer and order, you need a separate set of text boxes that are not data-bound to the CollectionViewSource. 通过在处理程序方法中设置 Visible 属性,可以控制用户在任意给定时间看到的网格。You'll control which grid the user sees at any given time by setting the Visible property in the handler methods. 最后,将 "删除" 按钮添加到 "订单" 网格中的每一行,以使用户能够删除单个订单。Finally, you add a Delete button to each row in the Orders grid to enable the user to delete an individual order.

首先,将这些样式添加到 Windows.Resources mainwindow.xaml 中的元素:First, add these styles to the Windows.Resources element in MainWindow.xaml :

接下来,将整个外部网格替换为以下标记:Next, replace the entire outer Grid with this markup:

Text="{Binding CustomerID, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true}"/>

Text="{Binding CompanyName, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true}"/>

Text="{Binding ContactName, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true}"/>

Text="{Binding ContactTitle, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true}"/>

Text="{Binding Address, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true}"/>

Text="{Binding City, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true}"/>

Text="{Binding Country, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true}"/>

Text="{Binding Fax, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true}"/>

Text="{Binding Phone, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true}"/>

Text="{Binding PostalCode, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true}"/>

Text="{Binding Region, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true}"/>

Text="{Binding CustomerID, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true}"/>

Text="{Binding CompanyName, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true }"/>

Text="{Binding ContactName, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true}"/>

Text="{Binding ContactTitle, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true}"/>

Text="{Binding Address, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true}"/>

Text="{Binding City, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true}"/>

Text="{Binding Country, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true}"/>

Text="{Binding Fax, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true}"/>

Text="{Binding Phone, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true}"/>

Text="{Binding PostalCode, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true}"/>

Text="{Binding Region, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true}"/>

Text="{Binding EmployeeID, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true}"/>

SelectedDate="{Binding OrderDate, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true, UpdateSourceTrigger=PropertyChanged}"/>

SelectedDate="{Binding RequiredDate, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true, UpdateSourceTrigger=PropertyChanged}"/>

SelectedDate="{Binding ShippedDate, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true, UpdateSourceTrigger=PropertyChanged}"/>

Text="{Binding ShipVia, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true}"/>

Text="{Binding Freight, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true}"/>

添加用于导航、添加、更新和删除的按钮Add buttons to navigate, add, update, and delete

在 Windows 窗体应用程序中,您将获得一个 BindingNavigator 对象,其中包含用于在数据库中的行间导航并执行基本 CRUD 操作的按钮。In Windows Forms applications, you get a BindingNavigator object with buttons for navigating through rows in a database and doing basic CRUD operations. WPF 并不提供 BindingNavigator,但可以很容易创建一个。WPF does not provide a BindingNavigator, but it is easy enough to create one. 使用水平 System.windows.controls.stackpanel> 中的按钮执行该操作,并将这些按钮与代码隐藏中的方法绑定的命令相关联。You do that with buttons inside a horizontal StackPanel, and associate the buttons with Commands that are bound to methods in the code behind.

命令逻辑分为以下四部分: (1) 命令, (2) 绑定, (3) 按钮, (4) 代码隐藏中的命令处理程序。There are four parts to the command logic: (1) the commands, (2) the bindings, (3) the buttons, and (4) the command handlers in the code-behind.

在 XAML 中添加命令、绑定和按钮Add commands, bindings, and buttons in XAML

首先,将 mainwindow.xaml 文件中的命令添加到 Windows.Resources 元素中:First, add the commands in the MainWindow.xaml file inside the Windows.Resources element:

System.windows.input.commandbinding> 将事件映射 RoutedUICommand 到代码隐藏中的方法。A CommandBinding maps a RoutedUICommand event to a method in the code behind. 将此 CommandBindings 元素添加到 Windows.Resources 结束标记后:Add this CommandBindings element after the Windows.Resources closing tag:

现在,请将添加到 " StackPanel 导航"、"添加"、"删除" 和 "更新" 按钮。Now, add the StackPanel with the navigation, add, delete, and update buttons. 首先,将以下样式添加到 Windows.Resources :First, add this style to Windows.Resources:

然后,将此代码粘贴到紧邻 RowDefinitions Grid XAML 页顶部的外部元素之后:Second, paste this code just after the RowDefinitions for the outer Grid element, toward the top of the XAML page:

向 Mainwindow.xaml 类添加命令处理程序Add command handlers to the MainWindow class

除 add 和 delete 方法外,代码隐藏是最少的。The code-behind is minimal except for the add and delete methods. 通过对 CollectionViewSource 的 View 属性调用方法来执行导航。Navigation is performed by calling methods on the View property of the CollectionViewSource. DeleteOrderCommandHandler演示如何对订单执行级联删除。The DeleteOrderCommandHandler shows how to perform a cascade delete on an order. 我们必须先删除与之关联的 Order_Details。We have to first delete the Order_Details that are associated with it. 向 UpdateCommandHandler 集合中添加新的客户或订单,或者只是使用用户在文本框中做出的更改来更新现有客户或订单。The UpdateCommandHandler adds a new customer or order to the collection, or else just updates an existing customer or order with the changes that the user made in the text boxes.

将这些处理程序方法添加到 MainWindow.xaml.cs 中的 mainwindow.xaml 类。Add these handler methods to the MainWindow class in MainWindow.xaml.cs. 如果 "客户" 表的 CollectionViewSource 具有不同的名称,则需要调整其中每个方法中的名称:If your CollectionViewSource for the Customers table has a different name, then you need to adjust the name in each of these methods:

private void LastCommandHandler(object sender, ExecutedRoutedEventArgs e)

{

custViewSource.View.MoveCurrentToLast();

}

private void PreviousCommandHandler(object sender, ExecutedRoutedEventArgs e)

{

custViewSource.View.MoveCurrentToPrevious();

}

private void NextCommandHandler(object sender, ExecutedRoutedEventArgs e)

{

custViewSource.View.MoveCurrentToNext();

}

private void FirstCommandHandler(object sender, ExecutedRoutedEventArgs e)

{

custViewSource.View.MoveCurrentToFirst();

}

private void DeleteCustomerCommandHandler(object sender, ExecutedRoutedEventArgs e)

{

// If existing window is visible, delete the customer and all their orders.

// In a real application, you should add warnings and allow the user to cancel the operation.

var cur = custViewSource.View.CurrentItem as Customer;

var cust = (from c in context.Customers

where c.CustomerID == cur.CustomerID

select c).FirstOrDefault();

if (cust != null)

{

foreach (var ord in cust.Orders.ToList())

{

Delete_Order(ord);

}

context.Customers.Remove(cust);

}

context.SaveChanges();

custViewSource.View.Refresh();

}

// Commit changes from the new customer form, the new order form,

// or edits made to the existing customer form.

private void UpdateCommandHandler(object sender, ExecutedRoutedEventArgs e)

{

if (newCustomerGrid.IsVisible)

{

// Create a new object because the old one

// is being tracked by EF now.

Customer newCustomer = new Customer

{

Address = add_addressTextBox.Text,

City = add_cityTextBox.Text,

CompanyName = add_companyNameTextBox.Text,

ContactName = add_contactNameTextBox.Text,

ContactTitle = add_contactTitleTextBox.Text,

Country = add_countryTextBox.Text,

CustomerID = add_customerIDTextBox.Text,

Fax = add_faxTextBox.Text,

Phone = add_phoneTextBox.Text,

PostalCode = add_postalCodeTextBox.Text,

Region = add_regionTextBox.Text

};

// Perform very basic validation

if (newCustomer.CustomerID.Length == 5)

{

// Insert the new customer at correct position:

int len = context.Customers.Local.Count();

int pos = len;

for (int i = 0; i < len; ++i)

{

if (String.CompareOrdinal(newCustomer.CustomerID, context.Customers.Local[i].CustomerID) < 0)

{

pos = i;

break;

}

}

context.Customers.Local.Insert(pos, newCustomer);

custViewSource.View.Refresh();

custViewSource.View.MoveCurrentTo(newCustomer);

}

else

{

MessageBox.Show("CustomerID must have 5 characters.");

}

newCustomerGrid.Visibility = Visibility.Collapsed;

existingCustomerGrid.Visibility = Visibility.Visible;

}

else if (newOrderGrid.IsVisible)

{

// Order ID is auto-generated so we don't set it here.

// For CustomerID, address, etc we use the values from current customer.

// User can modify these in the datagrid after the order is entered.

Customer currentCustomer = (Customer)custViewSource.View.CurrentItem;

Order newOrder = new Order()

{

OrderDate = add_orderDatePicker.SelectedDate,

RequiredDate = add_requiredDatePicker.SelectedDate,

ShippedDate = add_shippedDatePicker.SelectedDate,

CustomerID = currentCustomer.CustomerID,

ShipAddress = currentCustomer.Address,

ShipCity = currentCustomer.City,

ShipCountry = currentCustomer.Country,

ShipName = currentCustomer.CompanyName,

ShipPostalCode = currentCustomer.PostalCode,

ShipRegion = currentCustomer.Region

};

try

{

newOrder.EmployeeID = Int32.Parse(add_employeeIDTextBox.Text);

}

catch

{

MessageBox.Show("EmployeeID must be a valid integer value.");

return;

}

try

{

// Exercise for the reader if you are using Northwind:

// Add the Northwind Shippers table to the model.

// Acceptable ShipperID values are 1, 2, or 3.

if (add_ShipViaTextBox.Text == "1" || add_ShipViaTextBox.Text == "2"

|| add_ShipViaTextBox.Text == "3")

{

newOrder.ShipVia = Convert.ToInt32(add_ShipViaTextBox.Text);

}

else

{

MessageBox.Show("Shipper ID must be 1, 2, or 3 in Northwind.");

return;

}

}

catch

{

MessageBox.Show("Ship Via must be convertible to int");

return;

}

try

{

newOrder.Freight = Convert.ToDecimal(add_freightTextBox.Text);

}

catch

{

MessageBox.Show("Freight must be convertible to decimal.");

return;

}

// Add the order into the EF model

context.Orders.Add(newOrder);

ordViewSource.View.Refresh();

}

// Save the changes, either for a new customer, a new order

// or an edit to an existing customer or order.

context.SaveChanges();

}

// Sets up the form so that user can enter data. Data is later

// saved when user clicks Commit.

private void AddCommandHandler(object sender, ExecutedRoutedEventArgs e)

{

existingCustomerGrid.Visibility = Visibility.Collapsed;

newOrderGrid.Visibility = Visibility.Collapsed;

newCustomerGrid.Visibility = Visibility.Visible;

// Clear all the text boxes before adding a new customer.

foreach (var child in newCustomerGrid.Children)

{

var tb = child as TextBox;

if (tb != null)

{

tb.Text = "";

}

}

}

private void NewOrder_click(object sender, RoutedEventArgs e)

{

var cust = custViewSource.View.CurrentItem as Customer;

if (cust == null)

{

MessageBox.Show("No customer selected.");

return;

}

existingCustomerGrid.Visibility = Visibility.Collapsed;

newCustomerGrid.Visibility = Visibility.Collapsed;

newOrderGrid.UpdateLayout();

newOrderGrid.Visibility = Visibility.Visible;

}

// Cancels any input into the new customer form

private void CancelCommandHandler(object sender, ExecutedRoutedEventArgs e)

{

add_addressTextBox.Text = "";

add_cityTextBox.Text = "";

add_companyNameTextBox.Text = "";

add_contactNameTextBox.Text = "";

add_contactTitleTextBox.Text = "";

add_countryTextBox.Text = "";

add_customerIDTextBox.Text = "";

add_faxTextBox.Text = "";

add_phoneTextBox.Text = "";

add_postalCodeTextBox.Text = "";

add_regionTextBox.Text = "";

existingCustomerGrid.Visibility = Visibility.Visible;

newCustomerGrid.Visibility = Visibility.Collapsed;

newOrderGrid.Visibility = Visibility.Collapsed;

}

private void Delete_Order(Order order)

{

// Find the order in the EF model.

var ord = (from o in context.Orders.Local

where o.OrderID == order.OrderID

select o).FirstOrDefault();

// Delete all the order_details that have

// this Order as a foreign key

foreach (var detail in ord.Order_Details.ToList())

{

context.Order_Details.Remove(detail);

}

// Now it's safe to delete the order.

context.Orders.Remove(ord);

context.SaveChanges();

// Update the data grid.

ordViewSource.View.Refresh();

}

private void DeleteOrderCommandHandler(object sender, ExecutedRoutedEventArgs e)

{

// Get the Order in the row in which the Delete button was clicked.

Order obj = e.Parameter as Order;

Delete_Order(obj);

}

运行此应用程序Run the application

若要启用调试,请按 F5。To start debugging, press F5. 应会看到 "客户" 和 "订单" 数据已填充到网格中,导航按钮应按预期方式工作。You should see customer and order data populated in the grid, and the navigation buttons should work as expected. 在输入数据后,单击 " 提交 " 将新客户或订单添加到模型。Click on Commit to add a new customer or order to the model after you have entered the data. 单击 " 取消 " 以从新客户或新订单窗体中返回,而不保存数据。Click on Cancel to back out of a new customer or new order form without saving the data. 您可以直接在文本框中编辑现有客户和订单,这些更改会自动写入到模型中。You can make edits to existing customers and orders directly in the text boxes, and those changes are written to the model automatically.

请参阅See also

wpf mysql 框架_带有 WPF 和实体框架6的简单数据应用 - Visual Studio | Microsoft Docs相关推荐

  1. clickonce 部署能cs程序_配置 ClickOnce 信任提示行为 - Visual Studio | Microsoft Docs

    如何:配置 ClickOnce 信任提示行为How to: Configure the ClickOnce trust prompt behavior 11/04/2016 本文内容 您可以配置 Cl ...

  2. Entity Framework 实体框架的形成之旅--实体框架的开发的几个经验总结

    在前阵子,我对实体框架进行了一定的研究,然后把整个学习的过程开了一个系列,以逐步深入的方式解读实体框架的相关技术,期间每每碰到一些新的问题需要潜入研究.本文继续前面的主题介绍,着重从整体性的来总结一下 ...

  3. 参考框架 系统 基准_带有基准的前端框架的真实比较(2018更新)

    参考框架 系统 基准 by Jacek Schae 由Jacek Schae 带有基准的前端框架的真实比较(2018更新) (A Real-World Comparison of Front-End ...

  4. 参考框架 系统 基准_带有基准的前端框架的实际比较

    参考框架 系统 基准 by Jacek Schae 由Jacek Schae 带有基准的前端框架的实际比较 (A Real-World Comparison of Front-End Framewor ...

  5. php框架和不用框架_如何选择一个PHP框架

    php框架和不用框架 PHP是世界上最受欢迎的编程语言之一,而最近的PHP 7版本使这种服务器端编程语言比以往任何时候都更好,更稳定. PHP被广泛用于大型项目中. 例如,Facebook利用PHP来 ...

  6. java 数据校验框架_自己写的基于java Annotation(注解)的数据校验框架

    JavaEE6中提供了基于java Annotation(注解)的Bean校验框架,Hibernate也有类似的基于Annotation的数据校验功能,我在工作中,产品也经常需要使 用数据校验,为了方 ...

  7. netty 工控网关_开源纯C#工控网关+组态软件(九)定制Visual Studio

    一.引子 因为最近很忙(lan),很久没发博了.不少朋友对那个右键弹出菜单和连线的功能很感兴趣,因为VS本身是不包含这种功能的. 大家想这是什么鬼,怎么我的设计器没有,其实这是一个微软黑科技,如果用好 ...

  8. wpf 开源框架_.NET Core跨平台基础框架:10 篇热文汇总

    (给DotNet加星标,提升.Net技能) 本文精选了DotNet 2019年12月份的10篇热门文章.其中有技术分享.技术资源. 注:以下文章,点击标题即可阅读 <C#异步编程 > Ta ...

  9. java mysql框架_盘点 Java 数据库访问框架——究竟哪个更适合你

    本文将带您浏览和比较最受欢迎Java数据库访问框架(DAO层).假设您正在开发一个Java程序,有许多办法可以让您的应用连上数据库.下面会列举各数据库访问框架的适用场景,相信能够帮您选到适合项目的开发 ...

最新文章

  1. hiernate二级缓存区域
  2. 清远工贸职业技术学校清远大学城网
  3. html固定dl高度_HTML入门笔记1
  4. 痞子衡嵌入式:开启NXP-MCUBootUtility工具的BEE加密功能 - image_enc
  5. Datawhale组队-Pandas(下)文本数据(打卡)
  6. python网络-计算机网络基础(23)
  7. java同步方法必须是静态的吗_Java基础知识之synchronized同步方法、代码块、静态方法、静态代码块的区别...
  8. 荣耀20首现身!“保密壳”却暴露双排摄像头
  9. centos 6.4 更新源地址
  10. windows客户端连接linux服务器上的postmaster
  11. 捷联惯导系统学习7.4(车载惯性/里程仪组合导航 )
  12. red hat linux7下载地址,Red Hat Enterprise Linux 7 百度下载地址分享
  13. delphi android 音乐播放器,Mcool音乐播放器
  14. UART通信协议知识入门
  15. 360小程序搭载浏览器,再创PC时代又一春
  16. V2新品来袭 | 简约之选 无限可能
  17. 中国第二家傲途格精选酒店开业;德意志酒店集团所有旗舰酒店合入全新总品牌 | 美通企业日报...
  18. outlook自动保存html,outlook怎么编辑HTML源文件
  19. ubuntu 登录界面卡死解决方法
  20. 在数据库中删除某一列

热门文章

  1. 语音信号处理-基础(一):声学基础知识
  2. git拉取代码如何解决冲突_Git工具-git pull拉取代码时冲突的解决办法
  3. 计算机考研只考计算机网络的学校,计算机考研容易的学校有哪些 计算机考研难度排行榜...
  4. 计算机等级考试电子邮件的附件在哪里查看,​计算机等级考试详解:电子邮箱的地址组成结构!...
  5. 金字塔服务器连接文件夹,金字塔决策交易系统金钻版服务器及客户端安装配置说明...
  6. java计算机毕业设计营养分析系统源码+数据库+系统+lw文档+部署
  7. Failed to connect to github.com port 443: Operation timed out
  8. 机器视觉开源代码合集
  9. echarts自定义组件
  10. linux 抓包生成文件,Linux下使用libpcap进行网络抓包并保存到文件(函数介绍)