教學課程:使用 .NET 建立新的 WPF 應用程式
在本教學課程中,您將瞭解如何使用Visual Studio來建立新的 Windows Presentation Foundation (WPF) 應用程式。 使用 Visual Studio 時,您會將控件新增至視窗以設計應用程式的 UI,並處理來自這些控件的輸入事件,以與用戶互動。 在本教學課程結束時,您有一個簡單的應用程式,可將名稱新增至清單框。
在本教學課程中,您已:
- 建立新的 WPF 應用程式。
- 將控件新增至視窗。
- 處理控制項事件以提供應用程式功能。
- 執行應用程式。
以下是遵循本教學課程時所建立之應用程式的預覽:
必要條件
警告
不再支援 .NET 6。 建議您使用 .NET 9.0。
警告
不再支援 .NET 7。 建議您使用 .NET 9.0。
- Visual Studio 2022 17.8 版或更新版本
- 選取 [.NET 桌面開發工作負載]
- 選取 .NET 8 個別元件
- Visual Studio 2022 17.12 版或更新版本
- 選取 [.NET 桌面開發工作負載]
- 選取 .NET 9 個別元件
建立 WPF 應用程式
建立新應用程式的第一個步驟是開啟 Visual Studio,並從範本產生應用程式。
開啟 Visual Studio。
選取 [建立新專案]。
在 [搜尋範本] 方塊中,輸入 wpf,然後按 Enter 鍵。
在 [程式碼語言] 下拉式清單中,選擇 [C#] 或 [Visual Basic]。
在範本清單中,選取 [WPF 應用程式],然後選取 [下一步]。
重要
請勿選取 [WPF 應用程式 (.NET Framework)] 範本。
下圖顯示 C# 和 Visual Basic .NET 專案範本。 如果您套用程式 代碼語言 篩選,則只會顯示該語言的範本。
在 [設定新專案] 視窗中,執行下列動作:
- 在 [專案名稱] 方塊中,輸入 Names。
- 選取 [將解決方案與專案放置在同一個目錄] 核取方塊。
- 或者,選擇不同的 [位置] 來儲存您的程式碼。
- 選取下一步按鈕。
在 [其他資訊] 視窗中,針對 [目標 Framework] 選取 [.NET 6.0 (長期支援)]。 選取建立按鈕。
開啟 Visual Studio。
選取 [建立新專案]。
在 [搜尋範本] 方塊中,輸入 wpf,然後按 Enter 鍵。
在 [程式碼語言] 下拉式清單中,選擇 [C#] 或 [Visual Basic]。
在範本清單中,選取 [WPF 應用程式],然後選取 [下一步]。
重要
請勿選取 [WPF 應用程式 (.NET Framework)] 範本。
下圖顯示 C# 和 Visual Basic .NET 專案範本。 如果您套用程式 代碼語言 篩選,則只會顯示該語言的範本。
在 [設定新專案] 視窗中,執行下列動作:
- 在 [專案名稱] 方塊中,輸入 Names。
- 選取 [將解決方案與專案放置在同一個目錄] 核取方塊。
- 或者,選擇不同的 [位置] 來儲存您的程式碼。
- 選取下一步按鈕。
在 [其他資訊] 視窗中,針對 [目標 Framework] 選取 [.NET 7.0 (標準期間支援)]。 選取建立按鈕。
開啟 Visual Studio。
選取 [建立新專案]。
在 [搜尋範本] 方塊中,輸入 wpf,然後按 Enter 鍵。
在 [程式碼語言] 下拉式清單中,選擇 [C#] 或 [Visual Basic]。
在範本清單中,選取 [WPF 應用程式],然後選取 [下一步]。
重要
請勿選取 [WPF 應用程式 (.NET Framework)] 範本。
下圖顯示 C# 和 Visual Basic .NET 專案範本。 如果您套用程式 代碼語言 篩選,則只會顯示該語言的範本。
在 [設定新專案] 視窗中,執行下列動作:
- 在 [專案名稱] 方塊中,輸入 Names。
- 選取 [將解決方案與專案放置在同一個目錄] 核取方塊。
- 或者,選擇不同的 [位置] 來儲存您的程式碼。
- 選取下一步按鈕。
在 [其他資訊] 視窗中,選取目標 Framework 的 .NET 8.0 (長期支援)。 選取建立按鈕。
開啟 Visual Studio。
選取 [建立新專案]。
在 [搜尋範本] 方塊中,輸入 wpf,然後按 Enter 鍵。
在 [程式碼語言] 下拉式清單中,選擇 [C#] 或 [Visual Basic]。
在範本清單中,選取 [WPF 應用程式],然後選取 [下一步]。
重要
請勿選取 [WPF 應用程式 (.NET Framework)] 範本。
下圖顯示 C# 和 Visual Basic .NET 專案範本。 如果您套用程式 代碼語言 篩選,則只會顯示該語言的範本。
在 [設定新專案] 視窗中,執行下列動作:
- 在 [專案名稱] 方塊中,輸入 Names。
- 選取 [將解決方案與專案放置在同一個目錄] 核取方塊。
- 或者,選擇不同的 [位置] 來儲存您的程式碼。
- 選取下一步按鈕。
在 [其他資訊] 視窗中,選取目標 Framework 的 .NET 9.0 (標準字詞支援)。 選取建立按鈕。
產生應用程式之後,Visual Studio 應該開啟預設視窗 MainWindow 的 XAML 設計工具視窗。 如果看不到設計工具,請按兩下 方案總管 視窗中的MainWindow.xaml檔案,以開啟設計工具。
Visual Studio 的重要部分
Visual Studio 中 WPF 的支援有五個重要元件,您可以在建立應用程式時與其互動:
方案總管
您的所有項目檔、程式代碼、視窗、資源都會出現在此視窗中。
屬性
這個視窗會顯示您可以根據選取的項目來設定的屬性設定。 例如,如果您從 [方案總管] 選取項目,則會看到與檔案相關的屬性設定。 如果您在設計工具中選取物件,您會看到 項目的設定。 關於上一個影像,已在設計工具中選取視窗的標題列。
工具箱
工具箱包含您可以新增至設計介面的所有控制項。 若要將控件新增至目前介面,請按兩下控件或拖放介面上的控件。 通常會改用 XAML 程式代碼編輯器視窗來設計使用者介面(UI),同時使用 XAML 設計工具視窗來預覽結果。
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>
重要
如果您要在 Visual Basic 中撰寫程式代碼,XAML 會稍有不同,特別是 x:Class=".."
屬性。 Visual Basic 中的 XAML 會使用 物件的類別名稱,並將命名空間省略至 類別。
為了進一步瞭解 XAML,讓我們將其細分。 XAML 只是 WPF 用來建立 UI 所處理的 XML。 若要了解 XAML,請至少要熟悉 XML 的基本概念。
檔根 <Window>
目錄代表 XAML 檔案所描述的物件類型。 有八個已宣告的屬性,這些屬性通常屬於三個類別:
XML 命名空間
XML 命名空間會向 XML 提供結構,以判斷可於檔案中宣告的 XML 內容。
主要的
xmlns
屬性會匯入整個檔案的 XML 命名空間,在本案例中,其會對應至 WPF 所宣告的類型。 其他 XML 命名空間會宣告前置詞,並匯入 XAML 檔案的其他類型和物件。 例如,xmlns:local
命名空間會宣告local
前置詞,並對應至您的專案所宣告的物件,也就是在Names
程式碼命名空間中所宣告的物件。x:Class
屬性這個屬性會將 對應
<Window>
至程式代碼所定義的類型: MainWindow.xaml.cs 或 MainWindow.xaml.vb 檔案,也就是Names.MainWindow
C# 和MainWindow
Visual Basic 中的 類別。Title
屬性XAML 物件上宣告的任何一般屬性會設定該物件的屬性。 在本案例中,
Title
屬性會設定Window.Title
屬性。
變更視窗
在我們的範例應用程式中,此視窗太大,且標題列的描述不夠具體。 讓我們來修正此錯誤。
首先,按 F5 鍵或從選單中選取> [偵錯開始偵錯],以執行應用程式。
您會看到樣本所產生的預設視窗,其中未顯示任何控制件,以及 MainWindow 的標題:
將 設定
Title
為Names
,以變更視窗的標題。將 設定
Width
為180
和Height
260
,以變更視窗的大小。<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>
專案: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 設計工具顯示每個列和欄:
新增第一個控制項
現在已設定方格,我們可以開始將控件新增至該方格。 首先,從標籤控制項開始。
在 元素內
<Grid>
,在數據列和數據行定義之後,建立新的<Label>
專案。 將項目的內容設定為 的Names
字串值:<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
。請注意,標籤會佔用一半的視窗,因為它會自動定位到方格的第一個數據列和數據行。 第一個列不需要那麼大,因為這個列只用於標籤。
將第一個
<RowDefinition>
的Height
屬性從*
變更為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 欄。
建立名稱清單方塊
方格現已正確調整大小且標籤也已建立,接下來請在標籤下方的列上新增清單方塊控制項。
<ListBox />
在控件底下<Label>
宣告 控件。將
Grid.Row
屬性設為1
。將
x:Name
屬性設為lstNames
。為控制項命名後,就可以在程式碼後置中參考該控制項。 名稱會使用
x:Name
屬性指派給控制項。
XAML 看起來應該像這樣:
<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.Row
Grid.Column
時,堆疊面板會自動依序配置其每個子控制件。 它會「堆疊」彼此之後的每個控件。
<StackPanel>
在控件底下<ListBox>
宣告 控件。將
Grid.Row
屬性設為1
。將
Grid.Column
屬性設為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
非常不同10
。 margin 屬性是類型,而且可以解譯這兩個Thickness
值。 粗細會分別定義矩形框架每一邊 (、左、上、右、下) 的空間。 如果邊界的值是單一值,則四個邊都會使用這個值。在
<StackPanel>
控件內,建立<TextBox />
控件。- 將
x:Name
屬性設為txtName
。
- 將
最後,在
<TextBox>
之後,仍然在 內部<StackPanel>
,建立<Button>
控件。- 將
x:Name
屬性設為btnAdd
。 - 將
Margin
設定為0,5,0,0
。 - 將內容設定為
Add Name
。
- 將
XAML 看起來應該像這樣:
<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 屬性用來訂閱事件,就像用來設定屬性一樣。
<Button>
找出控件。將
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
執行應用程式
現在已處理事件,請執行應用程式。 隨即會顯示視窗,您可以在文字輸入框中輸入名稱,然後按一下按鈕加以新增。