教學課程:使用 .NET 建立新的 WPF 應用程式
在本簡短教學課程中,您將瞭解如何使用Visual Studio建立新的 Windows Presentation Foundation (WPF) 應用程式。 產生初始應用程式之後,您將瞭解如何新增控件,以及如何處理事件。 在本教學課程結束時,您將有一個簡單的應用程式,可將名稱新增至清單框。
在本教學課程中,您會了解如何:
- 建立新的 WPF 應用程式
- 將控件新增至表單
- 處理控制項事件以提供應用程式功能
- 執行應用程式
以下是您將在此教學課程中建置的應用程式預覽:
必要條件
提示
使用 Visual Studio 2022 17.4 版或更新版本,並安裝 .NET 7 和 .NET 6 個別元件。 Visual Studio 2022 17.4 版已新增 .NET 7 的支援。
建立 WPF 應用程式
建立新應用程式的第一個步驟是開啟Visual Studio,並從範本產生應用程式。
開啟 Visual Studio。
選取 [建立新專案]。
在 [ 搜尋範本 ] 方塊中,輸入 wpf,然後按 Enter。
在程式代碼語言下拉式清單中,選擇 [C#] 或 [Visual Basic]。
在範本清單中,選取 [WPF 應用程式 ],然後選取 [ 下一步]。
重要
請勿選取 WPF 應用程式 (.NET Framework) 範本。
下圖顯示 C# 和 Visual Basic .NET 專案範本。 如果您已套用程式 代碼語言 篩選,您會看到對應的範本。
在 [ 設定新專案 ] 視窗中,執行下列動作:
- 在 [項目名稱] 方塊中,輸入 [名稱]。
- 選取 [ 將方案與專案放在相同的目錄 ] 複選框。
- 或者,選擇不同的 位置 來儲存您的程序代碼。
- 選取下一步按鈕。
在 [其他資訊] 視窗中,選取目標 Framework 的 .NET 6.0 (長期支援)。 選取建立按鈕。
開啟 Visual Studio。
選取 [建立新專案]。
在 [ 搜尋範本 ] 方塊中,輸入 wpf,然後按 Enter。
在程式代碼語言下拉式清單中,選擇 [C#] 或 [Visual Basic]。
在範本清單中,選取 [WPF 應用程式 ],然後選取 [ 下一步]。
重要
請勿選取 WPF 應用程式 (.NET Framework) 範本。
下圖顯示 C# 和 Visual Basic .NET 專案範本。 如果您已套用程式 代碼語言 篩選,您會看到對應的範本。
在 [ 設定新專案 ] 視窗中,執行下列動作:
- 在 [項目名稱] 方塊中,輸入 [名稱]。
- 選取 [ 將方案與專案放在相同的目錄 ] 複選框。
- 或者,選擇不同的 位置 來儲存您的程序代碼。
- 選取下一步按鈕。
在 [其他資訊] 視窗中,選取目標 Framework 的 .NET 7.0 (標準字詞支援)。 選取建立按鈕。
產生應用程式之後,Visual Studio 應該開啟預設視窗 MainWindow 的 XAML 設計工具窗格。 如果看不到設計工具,請在 [方案總管] 窗格中按兩下MainWindow.xaml 檔案,以開啟設計工具。
Visual Studio 的重要部分
Visual Studio 中 WPF 的支援有五個重要元件,您會在建立應用程式時與其互動:
方案總管
您的所有項目檔、程式代碼、視窗、資源都會出現在此窗格中。
屬性
此窗格會顯示您可以根據選取的項目所設定的屬性設定。 例如,如果您從 方案總管 選取專案,您會看到與檔案相關的屬性設定。 如果您在設計師中選取物件,您會看到該專案的設定。
工具箱
工具箱包含您可以新增至表單的所有控制項。 若要將控件新增至目前窗體,請按兩下控件或拖放控件。
XAML 設計工具
這是 XAML 檔的設計工具。 它是互動式的,您可以從 [工具箱] 拖放物件。 藉由在設計工具中選取和移動專案,您可以可視化方式撰寫應用程式的使用者介面(UI)。
當設計工具與編輯器都可見時,其中一個變更會反映在另一個中。 當您在設計工具中選取專案時,[ 屬性 ] 窗格會顯示該物件的相關屬性和屬性。
XAML 程式碼編輯器
這是 XAML 檔的 XAML 程式代碼編輯器。 XAML 程式代碼編輯器是不使用設計工具手動製作 UI 的方法。 設計工具可能會在設計工具中加入控件時推斷控件上的屬性值。 XAML 程式代碼編輯器提供您更多的控制權。
當設計工具與編輯器都可見時,其中一個變更會反映在另一個中。 當您在程式代碼編輯器中巡覽文字插入號時,[ 屬性 ] 窗格會顯示該物件的相關屬性和屬性。
檢查 XAML
建立項目之後,會顯示 XAML 程式代碼編輯器,其中包含最少的 XAML 程式代碼以顯示視窗。 如果編輯器未開啟,請按兩下 方案總管中的MainWindow.xaml專案。 您應該會看到類似下列範例的 XAML:
<Window x:Class="Names.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:Names"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid>
</Grid>
</Window>
讓我們細分此 XAML 程式代碼,以進一步瞭解它。 XAML 只是 XML,可由 WPF 使用的編譯程序處理。 它會描述 WPF UI,並與 .NET 程式代碼互動。 若要瞭解 XAML,您應該至少熟悉 XML 的基本概念。
檔根 <Window>
代表 XAML 檔案所描述的物件類型。 已宣告八個屬性,它們通常屬於三個類別:
命名空間
XML 命名空間會提供 XML 的結構,以判斷檔案中可以宣告哪些 XML 內容。
main
xmlns
屬性會匯入整個檔案的 XML 命名空間,在此情況下,會對應至 WPF 所宣告的類型。 其他 XML 命名空間會宣告前置詞,並匯入 XAML 檔案的其他類型和物件。 例如,xmlns:local
命名空間會宣告前置詞,local
並對應至專案所宣告的物件,也就是在程式代碼命名空間中宣告的物件Names
。x:Class
屬性這個屬性會將 對應
<Window>
至程式代碼所定義的類型: MainWindow.xaml.cs 或 MainWindow.xaml.vb 檔案,也就是Names.MainWindow
類別。Title
屬性XAML 物件上宣告的任何一般屬性會設定該物件的屬性。 在此情況下,屬性會
Title
設定Window.Title
屬性。
變更視窗
首先,執行專案並查看預設輸出。 您會看到一個彈出視窗,其中沒有任何控制項,以及 MainWindow 的標題:
在我們的範例應用程式中,此視窗太大,標題列沒有描述性。 將 XAML 中的適當屬性變更為下列值,以變更視窗的標題和大小:
<Window x:Class="Names.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:Names"
mc:Ignorable="d"
Title="Names" Height="180" Width="260">
<Grid>
</Grid>
</Window>
準備版面配置
WPF 提供功能強大的版面配置系統,其中包含許多不同的版面配置控制件。 版面配置控制項有助於放置和調整子控件的大小,甚至可以自動進行。 在此 XAML 中提供給您的預設版面配置控制項是 <Grid>
控制項。
控件 Grid
可讓您定義數據列和數據行,就像數據表一樣,並將控件放在特定數據列和數據行組合的界限內。 您可以新增任意數目的子控件或其他版面配置控制件。Grid
例如,您可以將另一個 Grid
控件放在特定的數據列和數據行組合中,然後新的 Grid
可以定義更多數據列和數據行,並有自己的子系。
控制項 <Grid>
會定義控制項將會在其中的數據列和數據行。 網格線一律會宣告單一數據列和數據行,這表示方格預設為單一單元格。 這並沒有真正讓您在放置控件方面具有很大的彈性。
在新增數據列和數據行之前,請將新的屬性新增至 <Grid>
元素: Margin="10"
。 這會從視窗內塞入網格線,使其看起來更美觀。
接下來,定義兩個數據列和兩個數據行,將方格分成四個數據格:
<Grid Margin="10">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
</Grid>
在 XAML 程式代碼編輯器或 XAML 設計工具中選取方格,您會看到 XAML 設計工具會顯示每個資料列和資料列:
新增第一個控件
現在已建立方格,我們可以開始將控件新增至該方格。 首先,從標籤開始。 在 元素內建立新的<Label>
專案,並在數據列和數據行定義之後,併為其指定字串值Names
:<Grid>
<Grid Margin="10">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Label>Names</Label>
</Grid>
<Label>Names</Label>
定義內容 Names
。 有些控件會瞭解如何處理內容,有些則不會。 控件的內容會對應至 Content
屬性。 透過 XAML 屬性語法設定內容,您可以使用下列格式: <Label Content="Names" />
。 這兩種方式都會完成相同的動作,將標籤的內容設定為顯示文字 Names
。
不過,我們有問題,標籤會佔用視窗的一半,因為它會自動指派給方格的第一個數據列和數據行。 對於第一個數據列,我們不需要那麼多的空間,因為我們只會針對標籤使用該數據列。 將 Height
第一個 <RowDefinition>
的屬性從 *
變更為 Auto
。 值 Auto
會自動將網格線數據列的大小調整為其內容的大小,在此案例中為標籤控件。
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
請注意,設計工具現在會顯示佔用少量可用高度的標籤。 現在還有更多空間可供下一列佔用。 大部分的控件都會定義某種高度和寬度值,它們應該佔用最適合它們的高度和寬度值。 例如,標籤具有高度值,可確保您可以讀取它。
控件放置
讓我們來談談控件放置。 在上一節中建立的標籤會自動放在方格的第 0 列和資料行 0 中。 數據列和數據行的編號從 0 開始,並針對每個新數據列或數據行遞增 1。 控件不知道方格的任何專案,而且控制控制其在方格內的位置。 控件甚至可以放在一些其他配置控制件中,該控件有自己的規則集,定義如何放置控件。
當控件不知道方格時,如何告訴控件使用不同的數據列或數據行? 附加屬性! 網格線會利用 WPF 所提供的強大屬性系統。 方格會定義子控件可以宣告及使用的新屬性。 屬性實際上不存在於控件本身上,當控件新增至方格時,它們會由方格附加。
格線會定義兩個屬性,以判斷子控制的資料列和資料列位置: Grid.Row
和 Grid.Column
。 如果從控件省略這些屬性,則表示它們具有預設值 0,因此控件會放在方格的數據列 0
和數據行 0
中。 將 屬性設定Grid.Column
為 1
,嘗試變更 控制件的位置<Label>
:
<Label Grid.Column="1">Names</Label>
請注意您的標籤現在移至第二個數據行的方式。 您可以使用 Grid.Row
和 Grid.Column
附加屬性來放置我們將建立的下一個控件。 不過,現在請將標籤還原至數據行 0。
建立名稱清單框
現在,網格線已正確調整大小並建立標籤,請在標籤下方的數據列上新增清單框控制件。 清單框會位於數據列 1
和數據列 0
中。 我們也會提供此控制件的名稱 lstNames
。 一旦命名控件,就可以在程序代碼後置中參考它。 名稱會指派給具有 屬性的 x:Name
控件。
<Grid Margin="10">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Label>Names</Label>
<ListBox Grid.Row="1" x:Name="lstNames" />
</Grid>
新增其餘控制件
我們將新增的最後兩個控件是文本框和按鈕,使用者將用來輸入名稱以新增至清單框。 不過,我們不會嘗試為方格建立更多數據列和數據行,而是將這些控件放入版面 <StackPanel>
配置控件中。
堆疊面板與方格在控件的放置方式上不同。 當您告訴方格控件要與和 Grid.Column
附加屬性在一起Grid.Row
的位置時,堆棧面板會自動放置第一個控件,然後在控件之後放置下一個控件,繼續直到放置所有控件為止。 它會「堆疊」彼此下方的每個控件。
在 <StackPanel>
清單框之後建立控件,並將它放在方格列數據行 1
1
中。 新增名為 Margin
且值為 5,0,0,0
的另一個屬性:
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Label>Names</Label>
<ListBox Grid.Row="1" x:Name="lstNames" />
<StackPanel Grid.Row="1" Grid.Column="1" Margin="5,0,0,0">
</StackPanel>
屬性 Margin
先前在方格上使用,但我們只放入單一值 10
。 現在我們已在堆疊面板上使用的值 5,0,0,0
。 邊界是類型,而且可以解譯這兩個 Thickness
值。 粗細分別定義矩形框架、左、上、右、下、下兩側的空間。 如果邊界的值是單一值,則會針對四端使用該值。
接下來,在中<StackPanel>
建立 <TextBox>
和 <Button>
控件。
<StackPanel Grid.Row="1" Grid.Column="1" Margin="5,0,0,0">
<TextBox x:Name="txtName" />
<Button x:Name="btnAdd" Margin="0,5,0,0">Add Name</Button>
</StackPanel>
視窗的配置已完成。 不過,我們的應用程式沒有任何邏輯可實際運作。 接下來,我們需要將控件事件連結至程序代碼,並讓應用程式實際執行某些動作。
新增 Click 事件的程序代碼
<Button>
我們建立的事件Click
會在使用者按下按鈕時引發。 您可以訂閱此事件,並新增程式代碼以將名稱新增至清單框。 就像藉由新增 XAML 屬性在控件上設定屬性一樣,您可以使用 XAML 屬性來訂閱事件。 將 Click
屬性設定為 ButtonAddName_Click
<StackPanel Grid.Row="1" Grid.Column="1" Margin="5,0,0,0">
<TextBox x:Name="txtName" />
<Button x:Name="btnAdd" Margin="0,5,0,0" Click="ButtonAddName_Click">Add Name</Button>
</StackPanel>
現在您需要產生處理程式程式代碼。 以滑鼠右鍵按兩下 ButtonAddName_Click
,然後選取 [移至定義]。 此動作會在程式代碼後置中為您產生方法,其符合您輸入的處理程式名稱。
private void ButtonAddName_Click(object sender, RoutedEventArgs e)
{
}
Private Sub ButtonAddName_Click(sender As Object, e As RoutedEventArgs)
End Sub
接下來,新增下列程式代碼以執行下列三個步驟:
- 請確定文字框包含名稱。
- 驗證文字框中輸入的名稱不存在。
- 將名稱新增至清單框。
private void ButtonAddName_Click(object sender, RoutedEventArgs e)
{
if (!string.IsNullOrWhiteSpace(txtName.Text) && !lstNames.Items.Contains(txtName.Text))
{
lstNames.Items.Add(txtName.Text);
txtName.Clear();
}
}
Private Sub ButtonAddName_Click(sender As Object, e As RoutedEventArgs)
If Not String.IsNullOrWhiteSpace(txtName.Text) And Not lstNames.Items.Contains(txtName.Text) Then
lstNames.Items.Add(txtName.Text)
txtName.Clear()
End If
End Sub
執行應用程式
既然事件已經編碼,您可以按 F5 鍵或從功能表中選取> [偵錯開始偵錯] 來執行應用程式。 視窗隨即顯示,您可以在文字框中輸入名稱,然後按下按鈕加以新增。