使用 WPF 和 Entity Framework 6 建立簡單的資料應用程式Create a simple data application with WPF and Entity Framework 6

本逐步解說示範如何在 Visual Studio 中建立基本的「表單資料」應用程式。This walkthrough shows how to create a basic "forms over data" application in Visual Studio. 應用程式會使用 SQL Server LocalDB、Northwind 資料庫、Entity Framework 6 和 Windows Presentation Foundation。The app uses SQL Server LocalDB, the Northwind database, Entity Framework 6, and Windows Presentation Foundation. 它會示範如何使用主版詳細資料來執行基本的資料系結,而且它也有一個自訂系結導覽器,其中包含 [下一步]、[ 上移]、[移至開始]、[移至結束]、[更新]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、Entity Framework 和 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 資料提供者支援 Entity Framework,則也應該與其他 SQL database 產品搭配使用。If the ADO.NET data provider for that product supports Entity Framework, it should work with other SQL database products just as well.

  1. 如果您沒有 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.

  2. 依照下列步驟安裝 Northwind 範例資料庫:Install the Northwind sample database by following these steps:

    1. 在 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.

    2. Northwind transact-sql 腳本複製到剪貼簿。Copy the Northwind Transact-SQL script to your clipboard. 這個 T-sql 腳本會從頭開始建立 Northwind 資料庫,並在其中填入資料。This T-SQL script creates the Northwind database from scratch and populates it with data.

    3. 將 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.

  3. 新增 Northwind 的新連接Add new connections for Northwind.

設定專案Configure the project

  1. 在 Visual Studio 中,建立新C#的WPF 應用程式專案。In Visual Studio, create a new C# WPF App project.

  2. 新增 Entity Framework 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 套件功能表項目

  3. NuGet 套件管理員中,按一下 [流覽] 連結。In the NuGet Package Manager, click on the Browse link. Entity Framework 可能是清單中的最上層套件。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.

    Entity Framework NuGet 套件

  4. 現在您可以使用 Visual Studio 來建立以 Northwind 資料庫為基礎的模型。Now you can use Visual Studio to create a model based on the Northwind database.

建立模型Create the model

  1. 以滑鼠右鍵按一下方案總管中的專案節點,然後選擇 [加入 > 新專案]。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.

    Entity Framework 模型新專案

  2. 呼叫模型 Northwind_model,然後選擇 [確定]Call the model Northwind_model and choose OK. [實體資料模型精靈] 隨即開啟。The Entity Data Model Wizard opens. 從 [資料庫] 選擇EF Designer ,然後按 [下一步]Choose EF Designer from database and then click Next.

    來自資料庫的 EF 模型

  3. 在下一個畫面中,選擇您的 LocalDB Northwind 連接,然後按 [下一步]In the next screen, choose your LocalDB Northwind connection and click Next.

  4. 在 wizard 的下一個頁面中,選擇要包含在 Entity Framework 模型中的資料表、預存程式和其他資料庫物件。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.

    選擇模型的資料庫物件

  5. Wizard 會產生代表C# Entity Framework 模型的類別。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 save changes to the database. 您可以在 [Northwind_model] 節點下的方案總管中查看所有這些檔案:You can see all these files in Solution Explorer under the Northwind_model node:

    方案總管 EF 模型檔案

    .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.

  6. 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.)

  7. Ctrl+Shift+B以建立專案。Press Ctrl+Shift+B to build the project. 當組建完成時,[資料來源] wizard 可以看到模型類別。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.

  1. 從主功能表中,選擇 [專案] > [加入新的資料來源],以顯示 [資料來源設定向導]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:

    具有物件來源的資料來源設定向導

  2. 選取 [ Customer]。Select Customer. (訂單的來源會從 Customer 的 Orders 導覽屬性自動產生)。(Sources for Orders are automatically generated from the Orders navigation property in Customer.)

    將實體類別新增為數據源

  3. 按一下 [ 完成]。Click Finish.

  4. 在程式碼視圖中,流覽至mainwindow.xamlNavigate 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:

    <Grid.RowDefinitions>
            <RowDefinition Height="auto"/>
            <RowDefinition Height="auto"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>
    
  5. 現在開啟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 ,或選擇 View > 其他 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. 首先,按一下 [ Customers ] 下拉式方塊中的箭號,然後選擇 [詳細資料]。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. 根據預設,控制項會以垂直方式放在 grid 元素中,但此時您可以在表單上排列它們。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.

    客戶資料來源系結至個別控制項

    在 [程式碼] 視圖中,您現在可以在父方格的 [資料列 1] (中間資料列)中看到新的 Grid 元素。In the code view, you can now see a new Grid element in row 1 (the middle row) of the parent Grid. 父方格具有 DataContext 屬性,其參考已加入至 Windows.Resources 元素的 CollectionViewSource。The parent Grid has a DataContext attribute that refers to a CollectionViewSource that's been added to the Windows.Resources element. 假設該資料內容,當第一個文字方塊系結至Address時,該名稱會對應至 CollectionViewSource 中目前 Customer 物件的 Address 屬性。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.

    <Grid DataContext="{StaticResource customerViewSource}">
    
  6. 當客戶顯示在視窗的上半部時,您會想要查看其在下半部的訂單。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 屬性,而不要系結至不同的 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:

    將訂單類別拖曳為方格

  7. 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. 您也會新增「函式初始化」邏輯。You'll also add the 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. 讓我們將程式碼新增至 Window_Loaded,讓整個方法現在看起來像這樣:Let's add code to Window_Loaded so that the entire 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<T>.Local property    
        // to use the DbSet<T> as a binding source.   
        custViewSource.Source = context.Customers.Local;
    }
    
  8. 請按 F5Press 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 you'll make some changes manually in the XAML. 您也需要一些「表單」(實際上是格線),讓使用者加入新的客戶或訂單。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.

首先,將這些樣式加入至mainwindow.xaml中的 Windows.Resources 元素:First, add these styles to the Windows.Resources element in MainWindow.xaml:

<Style x:Key="Label" TargetType="{x:Type Label}" BasedOn="{x:Null}">
    <Setter Property="HorizontalAlignment" Value="Left"/>
    <Setter Property="VerticalAlignment" Value="Center"/>
    <Setter Property="Margin" Value="3"/>
    <Setter Property="Height" Value="23"/>
</Style>
<Style x:Key="CustTextBox" TargetType="{x:Type TextBox}" BasedOn="{x:Null}">
    <Setter Property="HorizontalAlignment" Value="Right"/>
    <Setter Property="VerticalAlignment" Value="Center"/>
    <Setter Property="Margin" Value="3"/>
    <Setter Property="Height" Value="26"/>
    <Setter Property="Width" Value="120"/>
</Style>

接下來,使用此標記來取代整個外部方格:Next, replace the entire outer Grid with this markup:

<Grid>
     <Grid.RowDefinitions>
         <RowDefinition Height="auto"/>
         <RowDefinition Height="auto"/>
         <RowDefinition Height="*"/>
     </Grid.RowDefinitions>
     <Grid x:Name="existingCustomerGrid" Grid.Row="1" HorizontalAlignment="Left" Margin="5" Visibility="Visible" VerticalAlignment="Top" Background="AntiqueWhite" DataContext="{StaticResource customerViewSource}">
         <Grid.ColumnDefinitions>
             <ColumnDefinition Width="Auto" MinWidth="233"/>
             <ColumnDefinition Width="Auto" MinWidth="397"/>
         </Grid.ColumnDefinitions>
         <Grid.RowDefinitions>
             <RowDefinition Height="Auto"/>
             <RowDefinition Height="Auto"/>
             <RowDefinition Height="Auto"/>
             <RowDefinition Height="Auto"/>
             <RowDefinition Height="Auto"/>
             <RowDefinition Height="Auto"/>
         </Grid.RowDefinitions>
         <Label Content="Customer ID:" Grid.Row="0" Style="{StaticResource Label}"/>
         <TextBox x:Name="customerIDTextBox" Grid.Row="0" Style="{StaticResource CustTextBox}"
                  Text="{Binding CustomerID, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true}"/>
         <Label Content="Company Name:" Grid.Row="1" Style="{StaticResource Label}"/>
         <TextBox x:Name="companyNameTextBox" Grid.Row="1" Style="{StaticResource CustTextBox}"
                  Text="{Binding CompanyName, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true}"/>
         <Label Content="Contact Name:" Grid.Row="2" Style="{StaticResource Label}"/>
         <TextBox x:Name="contactNameTextBox" Grid.Row="2" Style="{StaticResource CustTextBox}"
                  Text="{Binding ContactName, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true}"/>
         <Label Content="Contact title:" Grid.Row="3" Style="{StaticResource Label}"/>
         <TextBox x:Name="contactTitleTextBox" Grid.Row="3" Style="{StaticResource CustTextBox}"
                  Text="{Binding ContactTitle, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true}"/>
         <Label Content="Address:" Grid.Row="4" Style="{StaticResource Label}"/>
         <TextBox x:Name="addressTextBox" Grid.Row="4" Style="{StaticResource CustTextBox}"
                  Text="{Binding Address, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true}"/>
         <Label Content="City:" Grid.Column="1" Grid.Row="0" Style="{StaticResource Label}"/>
         <TextBox x:Name="cityTextBox" Grid.Column="1" Grid.Row="0" Style="{StaticResource CustTextBox}"
                  Text="{Binding City, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true}"/>
         <Label Content="Country:" Grid.Column="1" Grid.Row="1" Style="{StaticResource Label}"/>
         <TextBox x:Name="countryTextBox" Grid.Column="1" Grid.Row="1" Style="{StaticResource CustTextBox}"
                  Text="{Binding Country, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true}"/>
         <Label Content="Fax:" Grid.Column="1" Grid.Row="2" Style="{StaticResource Label}"/>
         <TextBox x:Name="faxTextBox" Grid.Column="1" Grid.Row="2" Style="{StaticResource CustTextBox}"
                  Text="{Binding Fax, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true}"/>
         <Label Content="Phone:" Grid.Column="1" Grid.Row="3" Style="{StaticResource Label}"/>
         <TextBox x:Name="phoneTextBox" Grid.Column="1" Grid.Row="3" Style="{StaticResource CustTextBox}"
                  Text="{Binding Phone, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true}"/>
         <Label Content="Postal Code:" Grid.Column="1" Grid.Row="4" VerticalAlignment="Center" Style="{StaticResource Label}"/>
         <TextBox x:Name="postalCodeTextBox" Grid.Column="1" Grid.Row="4" Style="{StaticResource CustTextBox}"
                  Text="{Binding PostalCode, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true}"/>
         <Label Content="Region:" Grid.Column="1" Grid.Row="5" Style="{StaticResource Label}"/>
         <TextBox x:Name="regionTextBox" Grid.Column="1" Grid.Row="5" Style="{StaticResource CustTextBox}"
                  Text="{Binding Region, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true}"/>
     </Grid>
     <Grid x:Name="newCustomerGrid" Grid.Row="1" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="5" DataContext="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}, Path=newCustomer, UpdateSourceTrigger=Explicit}" Visibility="Collapsed" Background="CornflowerBlue">
         <Grid.ColumnDefinitions>
             <ColumnDefinition Width="Auto" MinWidth="233"/>
             <ColumnDefinition Width="Auto" MinWidth="397"/>
         </Grid.ColumnDefinitions>
         <Grid.RowDefinitions>
             <RowDefinition Height="Auto"/>
             <RowDefinition Height="Auto"/>
             <RowDefinition Height="Auto"/>
             <RowDefinition Height="Auto"/>
             <RowDefinition Height="Auto"/>
             <RowDefinition Height="Auto"/>
         </Grid.RowDefinitions>
         <Label Content="Customer ID:" Grid.Row="0" Style="{StaticResource Label}"/>
         <TextBox x:Name="add_customerIDTextBox" Grid.Row="0" Style="{StaticResource CustTextBox}"
                  Text="{Binding CustomerID, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true}"/>
         <Label Content="Company Name:" Grid.Row="1" Style="{StaticResource Label}"/>
         <TextBox x:Name="add_companyNameTextBox" Grid.Row="1" Style="{StaticResource CustTextBox}"
                  Text="{Binding CompanyName, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true }"/>
         <Label Content="Contact Name:" Grid.Row="2" Style="{StaticResource Label}"/>
         <TextBox x:Name="add_contactNameTextBox" Grid.Row="2" Style="{StaticResource CustTextBox}"
                  Text="{Binding ContactName, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true}"/>
         <Label Content="Contact title:" Grid.Row="3" Style="{StaticResource Label}"/>
         <TextBox x:Name="add_contactTitleTextBox" Grid.Row="3" Style="{StaticResource CustTextBox}"
                  Text="{Binding ContactTitle, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true}"/>
         <Label Content="Address:" Grid.Row="4" Style="{StaticResource Label}"/>
         <TextBox x:Name="add_addressTextBox" Grid.Row="4" Style="{StaticResource CustTextBox}"
                  Text="{Binding Address, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true}"/>
         <Label Content="City:" Grid.Column="1" Grid.Row="0" Style="{StaticResource Label}"/>
         <TextBox x:Name="add_cityTextBox" Grid.Column="1" Grid.Row="0" Style="{StaticResource CustTextBox}"
                  Text="{Binding City, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true}"/>
         <Label Content="Country:" Grid.Column="1" Grid.Row="1" Style="{StaticResource Label}"/>
         <TextBox x:Name="add_countryTextBox" Grid.Column="1" Grid.Row="1" Style="{StaticResource CustTextBox}"
                  Text="{Binding Country, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true}"/>
         <Label Content="Fax:" Grid.Column="1" Grid.Row="2" Style="{StaticResource Label}"/>
         <TextBox x:Name="add_faxTextBox" Grid.Column="1" Grid.Row="2" Style="{StaticResource CustTextBox}"
                  Text="{Binding Fax, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true}"/>
         <Label Content="Phone:" Grid.Column="1" Grid.Row="3" Style="{StaticResource Label}"/>
         <TextBox x:Name="add_phoneTextBox" Grid.Column="1" Grid.Row="3" Style="{StaticResource CustTextBox}"
                  Text="{Binding Phone, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true}"/>
         <Label Content="Postal Code:" Grid.Column="1" Grid.Row="4" VerticalAlignment="Center" Style="{StaticResource Label}"/>
         <TextBox x:Name="add_postalCodeTextBox" Grid.Column="1" Grid.Row="4" Style="{StaticResource CustTextBox}"
                  Text="{Binding PostalCode, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true}"/>
         <Label Content="Region:" Grid.Column="1" Grid.Row="5" Style="{StaticResource Label}"/>
         <TextBox x:Name="add_regionTextBox" Grid.Column="1" Grid.Row="5" Style="{StaticResource CustTextBox}"
                  Text="{Binding Region, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true}"/>
     </Grid>
     <Grid x:Name="newOrderGrid" Grid.Row="1" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="5" DataContext="{Binding Path=newOrder, Mode=TwoWay}" Visibility="Collapsed" Background="LightGreen">
         <Grid.ColumnDefinitions>
             <ColumnDefinition Width="Auto" MinWidth="233"/>
             <ColumnDefinition Width="Auto" MinWidth="397"/>
         </Grid.ColumnDefinitions>
         <Grid.RowDefinitions>
             <RowDefinition Height="Auto"/>
             <RowDefinition Height="Auto"/>
             <RowDefinition Height="Auto"/>
             <RowDefinition Height="Auto"/>
             <RowDefinition Height="Auto"/>
             <RowDefinition Height="Auto"/>
             <RowDefinition Height="Auto"/>
         </Grid.RowDefinitions>
         <Label Content="New Order Form" FontWeight="Bold"/>
         <Label Content="Employee ID:"  Grid.Row="1" Style="{StaticResource Label}"/>
         <TextBox x:Name="add_employeeIDTextBox" Grid.Row="1" Style="{StaticResource CustTextBox}"
                  Text="{Binding EmployeeID, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true}"/>
         <Label Content="Order Date:"  Grid.Row="2" Style="{StaticResource Label}"/>
         <DatePicker x:Name="add_orderDatePicker" Grid.Row="2"  HorizontalAlignment="Right" Width="120"
                 SelectedDate="{Binding OrderDate, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true, UpdateSourceTrigger=PropertyChanged}"/>
         <Label Content="Required Date:" Grid.Row="3" Style="{StaticResource Label}"/>
         <DatePicker x:Name="add_requiredDatePicker" Grid.Row="3" HorizontalAlignment="Right" Width="120"
                  SelectedDate="{Binding RequiredDate, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true, UpdateSourceTrigger=PropertyChanged}"/>
         <Label Content="Shipped Date:"  Grid.Row="4"  Style="{StaticResource Label}"/>
         <DatePicker x:Name="add_shippedDatePicker"  Grid.Row="4"  HorizontalAlignment="Right" Width="120"
                 SelectedDate="{Binding ShippedDate, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true, UpdateSourceTrigger=PropertyChanged}"/>
         <Label Content="Ship Via:"  Grid.Row="5" Style="{StaticResource Label}"/>
         <TextBox x:Name="add_ShipViaTextBox"  Grid.Row="5" Style="{StaticResource CustTextBox}"
                  Text="{Binding ShipVia, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true}"/>
         <Label Content="Freight"  Grid.Row="6" Style="{StaticResource Label}"/>
         <TextBox x:Name="add_freightTextBox" Grid.Row="6" Style="{StaticResource CustTextBox}"
                  Text="{Binding Freight, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true}"/>
     </Grid>
     <DataGrid x:Name="ordersDataGrid" SelectionUnit="Cell" SelectionMode="Single" AutoGenerateColumns="False" CanUserAddRows="false" IsEnabled="True" EnableRowVirtualization="True" Width="auto" ItemsSource="{Binding Source={StaticResource customerOrdersViewSource}}" Margin="10,10,10,10" Grid.Row="2" RowDetailsVisibilityMode="VisibleWhenSelected">
         <DataGrid.Columns>
             <DataGridTemplateColumn>
                 <DataGridTemplateColumn.CellTemplate>
                     <DataTemplate>
                         <Button Content="Delete" Command="{StaticResource DeleteOrderCommand}" CommandParameter="{Binding}"/>
                     </DataTemplate>
                 </DataGridTemplateColumn.CellTemplate>
             </DataGridTemplateColumn>
             <DataGridTextColumn x:Name="customerIDColumn" Binding="{Binding CustomerID}" Header="Customer ID" Width="SizeToHeader"/>
             <DataGridTextColumn x:Name="employeeIDColumn" Binding="{Binding EmployeeID}" Header="Employee ID" Width="SizeToHeader"/>
             <DataGridTextColumn x:Name="freightColumn" Binding="{Binding Freight}" Header="Freight" Width="SizeToHeader"/>
             <DataGridTemplateColumn x:Name="orderDateColumn" Header="Order Date" Width="SizeToHeader">
                 <DataGridTemplateColumn.CellTemplate>
                     <DataTemplate>
                         <DatePicker SelectedDate="{Binding OrderDate, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true, UpdateSourceTrigger=PropertyChanged}"/>
                     </DataTemplate>
                 </DataGridTemplateColumn.CellTemplate>
             </DataGridTemplateColumn>
             <DataGridTextColumn x:Name="orderIDColumn" Binding="{Binding OrderID}" Header="Order ID" Width="SizeToHeader"/>
             <DataGridTemplateColumn x:Name="requiredDateColumn" Header="Required Date" Width="SizeToHeader">
                 <DataGridTemplateColumn.CellTemplate>
                     <DataTemplate>
                         <DatePicker SelectedDate="{Binding RequiredDate, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true, UpdateSourceTrigger=PropertyChanged}"/>
                     </DataTemplate>
                 </DataGridTemplateColumn.CellTemplate>
             </DataGridTemplateColumn>
             <DataGridTextColumn x:Name="shipAddressColumn" Binding="{Binding ShipAddress}" Header="Ship Address" Width="SizeToHeader"/>
             <DataGridTextColumn x:Name="shipCityColumn" Binding="{Binding ShipCity}" Header="Ship City" Width="SizeToHeader"/>
             <DataGridTextColumn x:Name="shipCountryColumn" Binding="{Binding ShipCountry}" Header="Ship Country" Width="SizeToHeader"/>
             <DataGridTextColumn x:Name="shipNameColumn" Binding="{Binding ShipName}" Header="Ship Name" Width="SizeToHeader"/>
             <DataGridTemplateColumn x:Name="shippedDateColumn" Header="Shipped Date" Width="SizeToHeader">
                 <DataGridTemplateColumn.CellTemplate>
                     <DataTemplate>
                         <DatePicker SelectedDate="{Binding ShippedDate, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true, UpdateSourceTrigger=PropertyChanged}"/>
                     </DataTemplate>
                 </DataGridTemplateColumn.CellTemplate>
             </DataGridTemplateColumn>
             <DataGridTextColumn x:Name="shipPostalCodeColumn" Binding="{Binding ShipPostalCode}" Header="Ship Postal Code" Width="SizeToHeader"/>
             <DataGridTextColumn x:Name="shipRegionColumn" Binding="{Binding ShipRegion}" Header="Ship Region" Width="SizeToHeader"/>
             <DataGridTextColumn x:Name="shipViaColumn" Binding="{Binding ShipVia}" Header="Ship Via" Width="SizeToHeader"/>
         </DataGrid.Columns>
     </DataGrid>
 </Grid>

新增按鈕以流覽、新增、更新和刪除Add buttons to navigate, add, update, and delete

在 Windows Forms 應用程式中,您會取得 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. 您可以使用水準 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.

命令邏輯有 fours 部分:(1)命令、(2)系結、(3)按鈕,以及(4)程式碼後置中的命令處理常式。There are fours 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

  1. 首先,將mainwindow.xaml中的命令新增至 Windows.Resources 元素內:First, add the commands in the MainWindow.xaml file inside the Windows.Resources element:

    <RoutedUICommand x:Key="FirstCommand" Text="First"/>
    <RoutedUICommand x:Key="LastCommand" Text="Last"/>
    <RoutedUICommand x:Key="NextCommand" Text="Next"/>
    <RoutedUICommand x:Key="PreviousCommand" Text="Previous"/>
    <RoutedUICommand x:Key="DeleteCustomerCommand" Text="Delete Customer"/>
    <RoutedUICommand x:Key="DeleteOrderCommand" Text="Delete Order"/>
    <RoutedUICommand x:Key="UpdateCommand" Text="Update"/>
    <RoutedUICommand x:Key="AddCommand" Text="Add"/>
    <RoutedUICommand x:Key="CancelCommand" Text="Cancel"/>
    
  2. CommandBinding 會將 RoutedUICommand 事件對應至程式碼後置中的方法。A CommandBinding maps a RoutedUICommand event to a method in the code behind. Windows.Resources 結束記號之後加入此 CommandBindings 元素:Add this CommandBindings element after the Windows.Resources closing tag:

    <Window.CommandBindings>
        <CommandBinding Command="{StaticResource FirstCommand}" Executed="FirstCommandHandler"/>
        <CommandBinding Command="{StaticResource LastCommand}" Executed="LastCommandHandler"/>
        <CommandBinding Command="{StaticResource NextCommand}" Executed="NextCommandHandler"/>
        <CommandBinding Command="{StaticResource PreviousCommand}" Executed="PreviousCommandHandler"/>
        <CommandBinding Command="{StaticResource DeleteCustomerCommand}" Executed="DeleteCustomerCommandHandler"/>
        <CommandBinding Command="{StaticResource DeleteOrderCommand}" Executed="DeleteOrderCommandHandler"/>
        <CommandBinding Command="{StaticResource UpdateCommand}" Executed="UpdateCommandHandler"/>
        <CommandBinding Command="{StaticResource AddCommand}" Executed="AddCommandHandler"/>
        <CommandBinding Command="{StaticResource CancelCommand}" Executed="CancelCommandHandler"/>
    </Window.CommandBindings>
    
  3. 現在,使用 [導覽]、[新增]、[刪除] 和 [更新] 按鈕來新增 StackPanelNow, add the StackPanel with the navigation, add, delete, and update buttons. 首先,將此樣式新增至 Windows.ResourcesFirst, add this style to Windows.Resources:

    <Style x:Key="NavButton" TargetType="{x:Type Button}" BasedOn="{x:Null}">
        <Setter Property="FontSize" Value="24"/>
        <Setter Property="FontFamily" Value="Segoe UI Symbol"/>
        <Setter Property="Margin" Value="2,2,2,0"/>
        <Setter Property="Width" Value="40"/>
        <Setter Property="Height" Value="auto"/>
    </Style>
    

    第二,將此程式碼貼入外部 Grid 元素的 RowDefinitions 後面,指向 XAML 頁面的頂端:Second, paste this code just after the RowDefinitions for the outer Grid element, toward the top of the XAML page:

    <StackPanel Orientation="Horizontal" Margin="2,2,2,0" Height="36" VerticalAlignment="Top" Background="Gainsboro" DataContext="{StaticResource customerViewSource}" d:LayoutOverrides="LeftMargin, RightMargin, TopMargin, BottomMargin">
        <Button Name="btnFirst" Content="|◄" Command="{StaticResource FirstCommand}" Style="{StaticResource NavButton}"/>
        <Button Name="btnPrev" Content="◄" Command="{StaticResource PreviousCommand}" Style="{StaticResource NavButton}"/>
        <Button Name="btnNext" Content="►" Command="{StaticResource NextCommand}" Style="{StaticResource NavButton}"/>
        <Button Name="btnLast" Content="►|" Command="{StaticResource LastCommand}" Style="{StaticResource NavButton}"/>
        <Button Name="btnDelete" Content="Delete Customer" Command="{StaticResource DeleteCustomerCommand}" FontSize="11" Width="120" Style="{StaticResource NavButton}"/>
        <Button Name="btnAdd" Content="New Customer" Command="{StaticResource AddCommand}" FontSize="11" Width="80" Style="{StaticResource NavButton}"/>
        <Button Content="New Order" Name="btnNewOrder" FontSize="11" Width="80" Style="{StaticResource NavButton}" Click="NewOrder_click"/>
        <Button Name="btnUpdate" Content="Commit" Command="{StaticResource UpdateCommand}" FontSize="11" Width="80" Style="{StaticResource NavButton}"/>
        <Button Content="Cancel" Name="btnCancel" Command="{StaticResource CancelCommand}" FontSize="11" Width="80" Style="{StaticResource NavButton}"/>
    </StackPanel>
    

將命令處理常式新增至 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. @No__t_0 顯示如何依循序執行串聯刪除。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. @No__t_0 會將新的客戶或訂單加入至集合,或只是以使用者在文字方塊中所做的變更來更新現有的客戶或訂單。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. 如果您的 [Customers] 資料表的 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.  

        Order newOrder = new Order()
        {
            OrderDate = add_orderDatePicker.SelectedDate,
            RequiredDate = add_requiredDatePicker.SelectedDate,
            ShippedDate = add_shippedDatePicker.SelectedDate
        };

        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;
    }

    Order newOrder = new Order();
    newOrder.CustomerID = cust.CustomerID;

    // Get address and other mostly constant fields from   
    // an existing order, if one exists  
    var coll = custViewSource.Source as IEnumerable<Customer>;
    var lastOrder = (from c in coll
                     from ord in c.Orders
                     select ord).LastOrDefault();
    if (lastOrder != null)
    {
        newOrder.ShipAddress = lastOrder.ShipAddress;
        newOrder.ShipCity = lastOrder.ShipCity;
        newOrder.ShipCountry = lastOrder.ShipCountry;
        newOrder.ShipName = lastOrder.ShipName;
        newOrder.ShipPostalCode = lastOrder.ShipPostalCode;
        newOrder.ShipRegion = lastOrder.ShipRegion;
    }

    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

若要開始偵錯,請按 F5To 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