WPF Windows Presentation Foundation
WPF (Windows Presentation Foundation) 是微软推出的用于创建桌面应用程序的框架,它是 .NET Framework 的一部分,提供了强大的图形、动画和用户界面功能。
核心特性
- XAML 声明式 UI:使用 XAML 标记语言创建用户界面
- 数据绑定:强大的数据绑定机制,支持双向绑定
- MVVM 模式:支持 Model-View-ViewModel 架构模式
- 丰富的控件库:提供大量内置控件和自定义控件支持
- 矢量图形:支持矢量图形和动画
- 主题和样式:灵活的样式和主题系统
- 多线程支持:支持多线程应用程序开发
系统要求
- Windows 7 或更高版本
- .NET Framework 3.5 或更高版本
- Visual Studio 2019/2022 或 Visual Studio Code
- Windows SDK
安装与配置
安装 .NET Framework
# 下载并安装 .NET Framework
# 访问 https://dotnet.microsoft.com/download创建 WPF 项目
# 使用 Visual Studio
# 1. 文件 -> 新建 -> 项目
# 2. 选择 "WPF 应用程序" 模板
# 3. 配置项目名称和位置
# 或使用命令行
dotnet new wpf -n MyWpfApp项目结构
MyWpfApp/
├── App.xaml # 应用程序定义
├── App.xaml.cs # 应用程序代码
├── MainWindow.xaml # 主窗口 UI
├── MainWindow.xaml.cs # 主窗口代码
├── Properties/
│ └── AssemblyInfo.cs # 程序集信息
├── Models/ # 数据模型
├── ViewModels/ # 视图模型
├── Views/ # 视图
└── Resources/ # 资源文件
├── Images/
├── Styles/
└── Themes/基础使用
创建主窗口
<!-- MainWindow.xaml -->
<Window x:Class="MyWpfApp.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="450" Width="800">
<Grid>
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
<TextBlock Text="Hello, WPF!"
FontSize="24"
HorizontalAlignment="Center"/>
<Button x:Name="myButton"
Content="Click me"
Click="myButton_Click"
Margin="0,10,0,0"/>
</StackPanel>
</Grid>
</Window>// MainWindow.xaml.cs
using System.Windows;
namespace MyWpfApp
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void myButton_Click(object sender, RoutedEventArgs e)
{
myButton.Content = "Clicked!";
}
}
}应用程序入口
// App.xaml.cs
using System.Windows;
namespace MyWpfApp
{
public partial class App : Application
{
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
MainWindow mainWindow = new MainWindow();
mainWindow.Show();
}
}
}UI 控件
基础控件
<!-- 按钮 -->
<Button Content="Primary Button"
Background="Blue"
Foreground="White"
Padding="10,5"/>
<!-- 文本框 -->
<TextBox Text="Enter text here"
Width="200"
Height="25"/>
<!-- 标签 -->
<Label Content="This is a label"
FontSize="14"
FontWeight="Bold"/>
<!-- 复选框 -->
<CheckBox Content="I agree to the terms"
IsChecked="True"/>
<!-- 单选按钮 -->
<StackPanel Orientation="Horizontal">
<RadioButton Content="Option 1"
GroupName="Options"
IsChecked="True"/>
<RadioButton Content="Option 2"
GroupName="Options"/>
</StackPanel>布局控件
<!-- 网格布局 -->
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="2*"/>
</Grid.ColumnDefinitions>
<TextBlock Grid.Row="0" Grid.Column="0" Text="Header"/>
<TextBlock Grid.Row="0" Grid.Column="1" Text="Content"/>
<TextBlock Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="2" Text="Footer"/>
</Grid>
<!-- 堆叠面板 -->
<StackPanel Orientation="Vertical" Margin="10">
<Button Content="Button 1" Margin="0,5"/>
<Button Content="Button 2" Margin="0,5"/>
<Button Content="Button 3" Margin="0,5"/>
</StackPanel>
<!-- 停靠面板 -->
<DockPanel>
<Button DockPanel.Dock="Top" Content="Top"/>
<Button DockPanel.Dock="Left" Content="Left"/>
<Button DockPanel.Dock="Right" Content="Right"/>
<Button Content="Fill"/>
</DockPanel>容器控件
<!-- 选项卡控件 -->
<TabControl>
<TabItem Header="Tab 1">
<TextBlock Text="Content for Tab 1"/>
</TabItem>
<TabItem Header="Tab 2">
<TextBlock Text="Content for Tab 2"/>
</TabItem>
</TabControl>
<!-- 列表视图 -->
<ListView>
<ListViewItem Content="Item 1"/>
<ListViewItem Content="Item 2"/>
<ListViewItem Content="Item 3"/>
</ListViewView>
<!-- 树视图 -->
<TreeView>
<TreeViewItem Header="Root">
<TreeViewItem Header="Child 1"/>
<TreeViewItem Header="Child 2"/>
</TreeViewItem>
</TreeView>数据绑定
简单绑定
<StackPanel>
<TextBox x:Name="InputTextBox"
Text="{Binding InputText, UpdateSourceTrigger=PropertyChanged}"/>
<TextBlock Text="{Binding InputText}"/>
</StackPanel>public class MainViewModel : INotifyPropertyChanged
{
private string _inputText;
public string InputText
{
get => _inputText;
set
{
_inputText = value;
OnPropertyChanged(nameof(InputText));
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}集合绑定
<ListView ItemsSource="{Binding Items}">
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Name}" Width="100"/>
<TextBlock Text="{Binding Description}"/>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>public class MainViewModel : INotifyPropertyChanged
{
private ObservableCollection<Item> _items;
public ObservableCollection<Item> Items
{
get => _items;
set
{
_items = value;
OnPropertyChanged(nameof(Items));
}
}
public MainViewModel()
{
Items = new ObservableCollection<Item>
{
new Item { Name = "Item 1", Description = "Description 1" },
new Item { Name = "Item 2", Description = "Description 2" }
};
}
}MVVM 模式
Model
public class User
{
public string Name { get; set; }
public string Email { get; set; }
public int Age { get; set; }
}ViewModel
public class UserViewModel : INotifyPropertyChanged
{
private User _user;
private ICommand _saveCommand;
public User User
{
get => _user;
set
{
_user = value;
OnPropertyChanged(nameof(User));
}
}
public ICommand SaveCommand
{
get => _saveCommand ??= new RelayCommand(Save);
}
private void Save()
{
// 保存用户数据
MessageBox.Show("User saved!");
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}View
<Window x:Class="MyWpfApp.UserWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="User Management" Height="300" Width="400">
<Grid Margin="10">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Label Grid.Row="0" Grid.Column="0" Content="Name:"/>
<TextBox Grid.Row="0" Grid.Column="1"
Text="{Binding User.Name, UpdateSourceTrigger=PropertyChanged}"/>
<Label Grid.Row="1" Grid.Column="0" Content="Email:"/>
<TextBox Grid.Row="1" Grid.Column="1"
Text="{Binding User.Email, UpdateSourceTrigger=PropertyChanged}"/>
<Label Grid.Row="2" Grid.Column="0" Content="Age:"/>
<TextBox Grid.Row="2" Grid.Column="1"
Text="{Binding User.Age, UpdateSourceTrigger=PropertyChanged}"/>
<Button Grid.Row="3" Grid.Column="1"
Content="Save"
Command="{Binding SaveCommand}"
HorizontalAlignment="Right"/>
</Grid>
</Window>样式和主题
定义样式
<Window.Resources>
<Style x:Key="CustomButtonStyle" TargetType="Button">
<Setter Property="Background" Value="#FF007ACC"/>
<Setter Property="Foreground" Value="White"/>
<Setter Property="Padding" Value="15,8"/>
<Setter Property="BorderThickness" Value="0"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Border Background="{TemplateBinding Background}"
CornerRadius="4">
<ContentPresenter HorizontalAlignment="Center"
VerticalAlignment="Center"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="#FF005A9E"/>
</Trigger>
</Style.Triggers>
</Style>
</Window.Resources>使用样式
<Button Style="{StaticResource CustomButtonStyle}"
Content="Custom Button"/>命令绑定
public class RelayCommand : ICommand
{
private readonly Action<object> _execute;
private readonly Func<object, bool> _canExecute;
public RelayCommand(Action<object> execute, Func<object, bool> canExecute = null)
{
_execute = execute ?? throw new ArgumentNullException(nameof(execute));
_canExecute = canExecute;
}
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
public bool CanExecute(object parameter)
{
return _canExecute == null || _canExecute(parameter);
}
public void Execute(object parameter)
{
_execute(parameter);
}
}异步编程
public class AsyncViewModel : INotifyPropertyChanged
{
private ObservableCollection<string> _items;
private ICommand _loadDataCommand;
public ObservableCollection<string> Items
{
get => _items;
set
{
_items = value;
OnPropertyChanged(nameof(Items));
}
}
public ICommand LoadDataCommand
{
get => _loadDataCommand ??= new RelayCommand(async _ => await LoadDataAsync());
}
private async Task LoadDataAsync()
{
try
{
// 模拟异步加载数据
await Task.Delay(2000);
Items = new ObservableCollection<string>
{
"Item 1", "Item 2", "Item 3"
};
}
catch (Exception ex)
{
MessageBox.Show($"Error: {ex.Message}");
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}资源管理
应用程序资源
<!-- App.xaml -->
<Application x:Class="MyWpfApp.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="MainWindow.xaml">
<Application.Resources>
<SolidColorBrush x:Key="PrimaryBrush" Color="#FF007ACC"/>
<SolidColorBrush x:Key="SecondaryBrush" Color="#FF6C757D"/>
</Application.Resources>
</Application>使用资源
<Button Background="{StaticResource PrimaryBrush}"
Content="Primary Button"/>最佳实践
性能优化
- 虚拟化:使用
VirtualizingStackPanel处理大量数据 - 延迟加载:使用
x:DeferLoadStrategy="Lazy" - 避免频繁的 UI 更新:使用
Dispatcher.BeginInvoke - 合理使用绑定:避免不必要的双向绑定
代码组织
- MVVM 模式:分离关注点,提高可维护性
- 命令模式:使用
ICommand处理用户交互 - 依赖注入:使用 IoC 容器管理依赖
- 单元测试:为 ViewModel 编写单元测试
常见问题
Q: 如何处理长时间运行的操作?
A: 使用异步编程和后台线程,避免阻塞 UI 线程。
Q: 如何实现数据验证?
A: 使用 IDataErrorInfo 或 INotifyDataErrorInfo 接口。
Q: 如何处理异常?
A: 使用全局异常处理器和 try-catch 块。
学习资源
相关技术
最近更新:12/9/2025, 2:17:56 AM