| header wpf delete label |
| https://learn.microsoft.com/zh-tw/visualstudio/data-tools/create-a-simple-data-application-with-wpf-and-entity-framework-6?view=vs |
|
|
豪情万千的花卷
7 月前 |
本教學課程說明如何在 Visual Studio 中 透過資料 應用程式建立基本表單。 應用程式使用 SQL Server LocalDB、Northwind 資料庫、Entity Framework 6(而非 Entity Framework Core),以及適用於 .NET Framework 的 Windows Presentation Foundation (WPF)(不是 .NET Core 或 .NET 5 或更新版本)。 它示範如何使用主數據檢視來執行基本數據系結,並包含具有執行下列動作之按鈕的自定義 BindingNavigator 控件:移至第一個、移動上一步、移至下一步、移至最後一個、刪除、新增、設定新順序、更新和取消。
本教學課程著重於在 Visual Studio 中使用數據工具,而且不會嘗試在任何深度說明基礎技術。 它假設您已熟悉 Extensible Application Markup Language (XAML)、Entity Framework 和 SQL。 雖然本教學課程中的程式代碼不會示範 Model-View-ViewModel (MVVM) 架構,這是 WPF 應用程式的標準,但您可以使用一些修改將程式代碼複製到您自己的 MVVM 應用程式。
若要檢視本教學課程的最終程序代碼,請參閱 Visual Studio教學課程範例 - EF6 。
在本教學課程中,您會:
已安裝 .NET 桌面開發 工作負載的 Visual Studio ,以及已安裝 Windows Communication Foundation 元件。 若要安裝:
SQL Server Express LocalDB。 如果您沒有 SQL Server Express LocalDB,您可以從 SQL Server 下載頁面 加以安裝。 或者,您可以將 Visual Studio 安裝程式 應用程式安裝為個別元件。
SQL Server 物件總管。 若要安裝,請在 Visual Studio 安裝程式 應用程式中安裝 資料儲存和處理 工作負載。
Entity Framework 6 工具。 當您安裝 .NET Desktop 開發 工作負載時,通常會安裝此程式。
下列範例使用 SQL Server Express LocalDB 和 Northwind 範例資料庫。 如果該產品 ADO.NET 數據提供者支援 Entity Framework,它也應該與其他 SQL 資料庫產品搭配使用。
依照下列步驟安裝 Northwind 範例資料庫:
在 Visual Studio 中,從 [檢視] 功能表開啟 [SQL Server 物件總管] 視窗。 展開 SQL Server 節點。 以滑鼠右鍵按下您的 LocalDB 實體例,然後選取 [新增查詢 ]。
查詢編輯器視窗隨即開啟。
將 Northwind Transact-SQL (T-SQL) 文稿 複製到剪貼簿。
將 T-SQL 腳本貼到查詢編輯器中,然後選擇 [ 執行 ]。
T-SQL 腳本查詢會建立 Northwind 資料庫,並填入數據。
為 Northwind 資料庫 新增連線 。
若要設定 WPF 應用程式專案,請遵循下列步驟:
在 Visual Studio 中,建立新的 C# WPF 應用程式 (.NET Framework) 專案。
新增 Entity Framework 6 的 NuGet 套件。 在 [ 方案總管] 中,選取項目節點。 在主選單中,選擇「 專案 > 管理 NuGet 套件 」。
在 NuGet 套件管理員 中,選取 [流覽] 連結。 搜尋並選取 EntityFramework 套件。 選取右窗格中的 [安裝 ],然後遵循提示。
[ 輸出 ] 視窗會顯示進度,並在安裝完成時通知您。
在 [選擇您的數據連線] 中,選取您的 LocalDB Northwind 連線(例如 ,localdb)\MSSQLLocalDB ),然後選取 [ 下一步 ]。
如果您沒有看到連線:
選擇 [新增連線 ]。 如果未選取 Microsoft SQL Server 作為 [ 連接屬性 ] 對話方塊中的 [資料源 ],請選取 [ 變更 ]。 在 [ 選擇數據源] 對話框中,選擇 [Microsoft SQL Server ],然後選取 [ 確定 ]。
在 [ 連線屬性] 對話框中,輸入 (localdb)\MSSQLLocalDB 作為 [伺服器名稱 ]。
針對 [選取或輸入資料庫名稱 ],選取 [Northwind ],然後選取 [ 確定 ]。
在 [選擇您的數據連線 ] 中,選取您的 LocalDB Northwind 連線,然後選取 [ 下一步 ]。
如果出現提示,請選擇您使用的 Entity Framework 版本,然後選取 [ 下一步 ]。
檔案
.tt
是一般用途,您必須編輯其中一個檔案,才能使用需要
ObservableCollection
物件的 WPF 數據系結。 請遵循下列步驟:
在 方案總管 中,展開 Northwind_model 節點,直到您找到 Northwind_model.tt 為止。 按兩下此檔案並進行下列編輯:
將出現的兩個 ICollection 替換為 ObservableCollection<T> 。
將第一個出現的 HashSet<T> 取代為 ObservableCollection<T> ,位置接近第 51 行。 請勿取代HashSet的第二次出現。
將唯一出現的 System.Collections.Generic (接近第 431 行) 取代為 System.Collections.ObjectModel 。
按 F5 以組建及執行專案。 應用程式第一次執行時,數據源精靈可以看到模型類別。
現在您已準備好將此模型連結至 XAML 頁面,以便檢視、巡覽及修改數據。
雖然您可以撰寫自己的數據系結程序代碼,但更容易讓Visual Studio為您執行。 若要這樣做,請遵循下列步驟:
從主功能表中,選擇 [ 專案 > 新增數據源 ] 以顯示 [數據源組態精靈 ]。 由於您要系結至模型類別,而不是系結至資料庫,請選擇 [物件 ]。 選取 下一步 。
在
[方案總管] 中
,按兩下專案中的
MainWindow.xaml
以編輯 XAML。 將
Title
從 MainWindow 變更為更具描述性的名稱,並將
Height
和
Width
分別增加到 600 和 800(您可以視需要稍後更改這些值)。
將這三個數據列定義新增至主要方格、一個用於瀏覽按鈕的數據列、一個用於客戶詳細數據,另一個用於顯示其訂單的方格:
<Grid.RowDefinitions>
<RowDefinition Height="auto"/>
<RowDefinition Height="auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
接下來,您會在 Customers 類別中的每個屬性以個別文本框顯示。 請遵循下列步驟:
在 [方案總管] 中,按兩下 MainWindow.xaml ,在設計工具中開啟它。
[數據源] 索引標籤會出現在 [工具箱] 附近的 Visual Studio 左窗格中。
若要開啟 [數據源 ] 視窗,請選取 [ 數據源 ] 索引卷標,或從功能表中選擇 [ 檢視>其他 Windows>數據源 ]。
在 [數據源] 中,選取 [ 客戶],然後從下拉式清單中選取 [ 詳細數據 ]。
將節點拖曳至設計區域的中間行。 如果您無法找到它,您可以選擇Grid.Row="1",然後在 XAML 中手動指定資料列。
根據預設,控件會垂直放置在網格線元素中,但您可以依您喜歡的方式排列這些控件。 例如,您可以將 [ 名稱] 文字框放在位址上方。 本教學課程的範例應用程式會將字段重新排序,並將其重新排列成兩個數據行。
在 XAML 檢視中,您現在可以在父方格的第 1 列(中間數據列)中看到新 Grid 元素。 父方格具有 DataContext 屬性,該屬性參考的是屬於 Windows.Resources 元素的 CollectionViewSource。 鑒於該數據內容,當第一個文本框系結至 Address 時,該名稱會對應至 Address 中目前 Customer 物件中的 CollectionViewSource屬性。
<Grid DataContext="{StaticResource customerViewSource}">
將 Order類別的 Customers 屬性拖曳到窗體的下半部,讓設計工具將它放在第 2 列。
當客戶顯示在表單的上半部時,您想要在下半部看到他們的訂單。 您可以在單一方格檢視控件中顯示訂單。 若要讓主數據系結如預期般運作,請務必系結至 Orders 類別中的 Customers 屬性,而不是系結至個別 Orders 節點。
Visual Studio 現在會產生將 UI 控件連線到模型中事件的所有系結程序代碼。
若要查看某些數據,請撰寫程式代碼以填入模型。 導航至 MainWindow.xaml.cs 並新增一個數據成員至 MainWindow 類別以供數據內容使用。
為您產生的這個物件,就像控制項一樣,能夠追蹤模型中的變更和事件。
將 CollectionViewSource 客戶和訂單的數據成員,以及相關聯的建構函式初始化邏輯新增至現有的建構函式 MainWindow()。 課程的第一部分看起來應該像這樣:
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;
如果不存在,請新增 using 指示詞以將 System.Data.Entity 擴充方法帶入 Load 範圍。
using System.Data.Entity;
向下捲動並尋找 Window_Loaded 事件處理程式。 請注意,Visual Studio 已新增 CollectionViewSource 物件。 此物件代表 NorthwindEntities 您在建立模型時選取的物件。 因為您已經新增它,所以這裡不需要它。 取代 中的 Window_Loaded 程式代碼,讓 方法看起來像這樣:
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;
按 F5。
您應該會看到第一個擷取到 CollectionViewSource 的數據格中客戶及其訂單的詳細數據。 您將在下一節中修正格式設定。 您也可以建立方法來檢視其他記錄,並執行基本建立、讀取、更新和刪除 (CRUD) 作業。
調整頁面設計,並新增新客戶和訂單的方格
Visual Studio 所產生的預設排列不適合您的應用程式,因此我們會在這裡提供最終的 XAML,以複製到您的程式代碼。 您也需要一些方格,讓用戶能夠新增客戶或訂單。
若要新增客戶和訂單,請建立一組未系結至 CollectionViewSource的數據個別文本框。 您可以在處理程式方法中設定 Visible 屬性,以控制使用者在任何指定時間看到的方格。 最後,您會將 [刪除] 按鈕新增至 [訂單] 方格中的每個數據列,讓用戶能夠刪除個別訂單。
開啟 MainWindow.xaml ,並將下列樣式新增至 Windows.Resources 專案:
<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>
以這個標記取代整個外部方格:
<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>
新增按鈕以巡覽、新增、更新和刪除
在 Windows Forms 應用程式中,您有一個 BindingNavigator 物件,其中包含用來巡覽資料庫中數據列並執行基本 CRUD 作業的按鈕。 雖然 WPF 不提供 BindingNavigator,但是只要在水準 StackPanel內建立按鈕,並將按鈕與系結至程式代碼後置檔案中方法的命令產生關聯,即可輕鬆地建立一個按鈕。
命令邏輯有四個部分:
程序代碼後置中的命令處理程式
在 XAML 中新增命令、系結和按鈕
在MainWindow.xaml檔案中,在Windows.Resources元素內新增命令,如下所示:
<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"/>
會將 CommandBinding 事件映射到程式碼後端中的方法。 將此CommandBindings元素新增在Windows.Resources結尾標記之後,如下所示:
<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>
在StackPanel上新增導覽、新增、刪除和更新按鈕。 將此樣式新增至 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>
將此程式碼直接貼在 XAML 頁面接近頂端、外層Grid元素的RowDefinitions之後:
<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 類別
MainWindow.xaml.cs 中的程式代碼後置非常簡單,除了新增和刪除方法之外:
若要巡覽,請在 的CollectionViewSource屬性上View呼叫 方法。
若要在訂單上執行串聯刪除,請使用 DeleteOrderCommandHandler ,如程式代碼範例所示。 不過,您必須先刪除訂單的相關 Order_Details。
UpdateCommandHandler使用 將客戶或訂單新增至集合,或使用使用者在文本框中所做的變更來更新現有的客戶或訂單。
將這些處理程式方法新增至 MainWindow 中的 MainWindow.xaml.cs類別。 如果您的 CollectionViewSource 客戶資料表的名稱不同,您必須在每個方法中調整名稱:
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);
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
newOrder.EmployeeID = Int32.Parse(add_employeeIDTextBox.Text);
catch
MessageBox.Show("EmployeeID must be a valid integer value.");
return;
// 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);
MessageBox.Show("Shipper ID must be 1, 2, or 3 in Northwind.");
return;
catch
MessageBox.Show("Ship Via must be convertible to int");
return;
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);
執行 WPF 應用程式
若要開始偵錯,請按 F5。 確認客戶和訂單數據已填入方格中,且導覽按鈕會如預期般運作。
選取 提交,以將新客戶或訂單新增至模型,前提是您已輸入數據。
選取 取消 以退出新的客戶或新訂單窗體,而不儲存資料。
若要直接對現有客戶和訂單進行編輯,請使用文本框,以自動將這些變更寫入模型。
適用於 .NET 的 Visual Studio 資料工具
Entity Framework 文件