C# WPF 基础知识学习(三)

一、WPF 概述

1.1 什么是 WPF

Windows Presentation Foundation(WPF)是微软为开发 Windows 桌面应用程序而推出的一个 UI 框架。它引入了许多先进的技术和概念,如基于矢量图形的渲染、数据绑定、样式和模板等,使得开发者能够创建出具有丰富视觉效果和交互性的应用程序。与传统的 Windows Forms 相比,WPF 更加注重用户体验和界面设计的灵活性。

1.2 WPF 的优势

  • 声明式编程:通过 XAML(可扩展应用程序标记语言),开发者可以以声明的方式定义界面,将界面设计与业务逻辑分离,提高开发效率和可维护性。
  • 强大的图形渲染:基于 DirectX 技术,WPF 能够实现高质量的 2D 和 3D 图形渲染,支持硬件加速,确保复杂图形和动画的流畅显示。
  • 数据绑定:提供了强大的数据绑定机制,使得 UI 元素能够自动反映数据源的变化,并且可以双向绑定,方便数据的交互和更新。
  • 样式和模板:允许开发者定义统一的样式和模板,实现界面的一致性和复用性,同时可以轻松地定制控件的外观和行为。
  • 动画支持:内置了丰富的动画系统,包括线性动画、关键帧动画等,能够创建出生动的用户界面。

1.3 WPF 的应用场景

  • 企业级应用:如办公软件、数据分析工具等,需要提供复杂的界面和交互功能,WPF 可以满足这些需求。
  • 多媒体应用:视频播放器、音频编辑软件等,利用 WPF 的图形和多媒体处理能力,实现高质量的媒体播放和编辑功能。
  • 游戏开发:虽然不是主流的游戏开发平台,但 WPF 可以用于开发一些小型的 2D 游戏,尤其是需要精美的界面和动画效果的游戏。

二、创建 WPF 项目

2.1 安装开发环境

要开始开发 WPF 应用程序,需要安装 Visual Studio。可以从微软官方网站下载并安装最新版本的 Visual Studio,在安装过程中选择 ".NET 桌面开发" 工作负载,其中包含了开发 WPF 应用所需的工具和框架。

2.2 创建新的 WPF 项目

  1. 打开 Visual Studio,选择 "创建新项目"。
  2. 在搜索框中输入 "WPF 应用",选择适合的项目模板,如 "WPF 应用(.NET Framework)" 或 "WPF 应用(.NET Core)",根据自己的需求选择。
  3. 输入项目名称和存储位置,然后点击 "创建" 按钮。

2.3 项目结构

创建好的 WPF 项目包含以下主要文件和文件夹:

  • App.xaml 和 App.xaml.cs:App.xaml 是应用程序的入口文件,定义了应用程序的资源和启动设置;App.xaml.cs 是对应的代码文件,包含应用程序的启动逻辑。
  • MainWindow.xaml 和 MainWindow.xaml.cs:MainWindow.xaml 是主窗口的 XAML 文件,用于定义窗口的界面布局和元素;MainWindow.xaml.cs 是对应的代码文件,包含窗口的事件处理和业务逻辑。
  • Properties 文件夹:包含项目的属性设置,如应用程序图标、版本信息等。
  • References 文件夹:列出了项目所引用的程序集,开发者可以根据需要添加或删除引用。

三、XAML 基础

3.1 XAML 简介

XAML 是一种基于 XML 的标记语言,用于描述 WPF 应用程序的用户界面。它通过标签和属性的方式来定义界面元素的结构和外观,使得界面设计更加直观和易于理解。

3.2 XAML 语法

  • 元素和属性:XAML 中的元素对应于.NET 类型,元素名称通常与类型名称相同。属性用于设置元素的特性,例如:
XML 复制代码
<Button Content="Click Me" Width="100" Height="30" />

这里的 <Button> 是元素,ContentWidthHeight 是属性。

  • 嵌套元素:元素可以嵌套在其他元素内部,形成层次结构。例如:
XML 复制代码
<StackPanel>
    <TextBlock Text="Hello, World!" />
    <Button Content="OK" />
</StackPanel>

<StackPanel> 是一个容器元素,包含了一个 <TextBlock> 和一个 <Button>

  • 命名空间:XAML 使用命名空间来引用不同的类型。在每个 XAML 文件的根元素中,通常会定义默认命名空间和其他需要的命名空间。例如:
XML 复制代码
<Window x:Class="WpfApp1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <!-- 窗口内容 -->
</Window>

默认命名空间 http://schemas.microsoft.com/winfx/2006/xaml/presentation 包含了 WPF 的核心 UI 元素类型,xmlns:x 引用的命名空间用于 XAML 语言本身的特性,如 x:Class 用于指定代码隐藏文件中对应的类。

3.3 常用 XAML 元素

  • 布局容器
    • Grid :将界面划分为行和列的网格,子元素可以通过 Grid.RowGrid.Column 附加属性指定在网格中的位置。例如:
XML 复制代码
<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto" />
        <RowDefinition Height="*" />
    </Grid.RowDefinitions>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="Auto" />
        <ColumnDefinition Width="*" />
    </Grid.ColumnDefinitions>
    <Button Content="Top - Left" Grid.Row="0" Grid.Column="0" />
    <Button Content="Top - Right" Grid.Row="0" Grid.Column="1" />
    <Button Content="Bottom - Left" Grid.Row="1" Grid.Column="0" />
    <Button Content="Bottom - Right" Grid.Row="1" Grid.Column="1" />
</Grid>
  • StackPanel :按照水平或垂直方向排列子元素,通过 Orientation 属性可以设置排列方向,默认是垂直方向。例如:
XML 复制代码
<StackPanel Orientation="Horizontal">
    <Button Content="Button 1" />
    <Button Content="Button 2" />
    <Button Content="Button 3" />
</StackPanel>
  • WrapPanel:子元素会按照指定的方向依次排列,当一行或一列排满时,会自动换行或换列。例如:
XML 复制代码
<WrapPanel>
    <Button Content="Short Button" />
    <Button Content="A Longer Button" />
    <Button Content="Another Button" />
</WrapPanel>
  • DockPanel :子元素可以停靠在面板的边缘,通过 DockPanel.Dock 附加属性设置停靠位置。例如:
XML 复制代码
<DockPanel>
    <Button Content="Top" DockPanel.Dock="Top" />
    <Button Content="Bottom" DockPanel.Dock="Bottom" />
    <Button Content="Left" DockPanel.Dock="Left" />
    <Button Content="Right" DockPanel.Dock="Right" />
    <Button Content="Center" />
</DockPanel>
  • 控件元素
    • Button :用于触发操作,通过 Content 属性设置按钮显示的文本或其他内容,通过 Click 事件处理按钮的点击操作。
XML 复制代码
<Button Content="Submit" Click="Button_Click" />

在后台代码中:

private void Button_Click(object sender, RoutedEventArgs e)
{
    MessageBox.Show("Button clicked!");
}
  • TextBox :用于输入文本,通过 Text 属性获取或设置文本内容,通过 TextChanged 事件响应文本的变化。
XML 复制代码
<TextBox TextChanged="TextBox_TextChanged" />

后台代码:

private void TextBox_TextChanged(object sender, TextChangedEventArgs e)
{
    TextBox textBox = (TextBox)sender;
    string text = textBox.Text;
    // 处理文本变化逻辑
}
  • ComboBox :下拉列表框,用户可以从预定义的选项中选择一个值。通过 ItemsSource 属性绑定数据源,通过 SelectedItemSelectedValue 属性获取当前选中的项。
XML 复制代码
<ComboBox ItemsSource="{Binding MyItems}" SelectedValue="{Binding SelectedItem}" />

假设在 ViewModel 中定义了 MyItems 集合和 SelectedItem 属性:

public class ViewModel
{
    public ObservableCollection<string> MyItems { get; set; }
    public string SelectedItem { get; set; }

    public ViewModel()
    {
        MyItems = new ObservableCollection<string>() { "Option 1", "Option 2", "Option 3" };
    }
}
  • CheckBox :复选框控件,用于表示布尔值的选择状态。通过 IsChecked 属性获取或设置复选框的选中状态,通过 CheckedUnchecked 事件响应状态变化。
XML 复制代码
<CheckBox Content="Remember Me" IsChecked="{Binding IsRememberMe}" />

在 ViewModel 中定义 IsRememberMe 属性:

private bool _isRememberMe;
public bool IsRememberMe
{
    get { return _isRememberMe; }
    set
    {
        _isRememberMe = value;
        OnPropertyChanged(nameof(IsRememberMe));
    }
}
  • RadioButton :单选按钮,一组单选按钮中只能有一个被选中。通过 GroupName 属性将多个单选按钮分组,通过 IsChecked 属性判断是否被选中。
XML 复制代码
<StackPanel>
    <RadioButton Content="Male" GroupName="Gender" IsChecked="{Binding Gender, Converter={StaticResource GenderConverter}, ConverterParameter=Male}" />
    <RadioButton Content="Female" GroupName="Gender" IsChecked="{Binding Gender, Converter={StaticResource GenderConverter}, ConverterParameter=Female}" />
</StackPanel>

这里使用了一个转换器 GenderConverter 来将 ViewModel 中的 Gender 属性值与单选按钮的选中状态进行转换。

四、数据绑定

4.1 数据绑定的概念

数据绑定是 WPF 的核心特性之一,它建立了 UI 元素(绑定目标)和数据源(绑定源)之间的连接,使得 UI 元素能够自动反映数据源的变化,并且可以将用户在 UI 上的操作反馈到数据源。

4.2 绑定模式

  • OneWay:数据从绑定源流向绑定目标,当绑定源属性值发生变化时,绑定目标属性会自动更新,但绑定目标的变化不会影响绑定源。常用于显示只读数据的场景,如显示数据库中的记录。
XML 复制代码
<TextBlock Text="{Binding ReadOnlyProperty, Mode=OneWay}" />
  • TwoWay:数据在绑定源和绑定目标之间双向流动,当绑定源属性值变化时,绑定目标更新;当绑定目标属性值变化时,绑定源也会相应更新。常用于需要用户输入并更新数据的场景,如编辑表单。
XML 复制代码
<TextBox Text="{Binding EditableProperty, Mode=TwoWay}" />
  • OneTime:数据在初始化时从绑定源流向绑定目标,之后绑定源的变化不会再影响绑定目标。适用于数据在应用程序运行过程中不会改变的情况,如显示应用程序的版本号。
XML 复制代码
<TextBlock Text="{Binding AppVersion, Mode=OneTime}" />

4.3 实现数据绑定

  • 创建数据源 :通常会创建一个 ViewModel 类来作为数据源。ViewModel 类应该实现 INotifyPropertyChanged 接口,以便在属性值发生变化时通知绑定目标更新。例如:
cs 复制代码
public class UserViewModel : INotifyPropertyChanged
{
    private string _name;
    public string Name
    {
        get { return _name; }
        set
        {
            _name = value;
            OnPropertyChanged(nameof(Name));
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;
    protected virtual void OnPropertyChanged(string propertyName)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}
  • 设置 DataContext :在窗口或控件的代码隐藏文件中,将 ViewModel 的实例设置为 DataContext,这样 XAML 中的绑定就可以找到对应的数据源。
cs 复制代码
public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        UserViewModel viewModel = new UserViewModel();
        DataContext = viewModel;
    }
}
  • 在 XAML 中进行绑定 :使用 Binding 标记扩展将 UI 元素的属性绑定到 ViewModel 的属性上。
XML 复制代码
<TextBox Text="{Binding Name}" />

4.4 绑定到集合

在实际应用中,经常需要将 UI 元素绑定到集合数据上,例如将 ListViewComboBox 绑定到一个 ObservableCollectionObservableCollection 是一个动态集合,当集合中的元素发生添加、删除或修改操作时,会自动通知绑定的 UI 元素进行更新。

以下是一个将 ListView 绑定到 ObservableCollection 的示例:

cs 复制代码
public class EmployeeViewModel
{
    public ObservableCollection<Employee> Employees { get; set; }

    public EmployeeViewModel()
    {
        Employees = new ObservableCollection<Employee>
        {
            new Employee { Name = "John Doe", Age = 30 },
            new Employee { Name = "Jane Smith", Age = 25 },
            new Employee { Name = "Bob Johnson", Age = 35 }
        };
    }
}

public class Employee
{
    public string Name { get; set; }
    public int Age { get; set; }
}

在 XAML 中:

XML 复制代码
<Window.Resources>
    <DataTemplate x:Key="EmployeeTemplate">
        <StackPanel Orientation="Horizontal">
            <TextBlock Text="{Binding Name}" Margin="5" />
            <TextBlock Text="{Binding Age}" Margin="5" />
        </StackPanel>
    </DataTemplate>
</Window.Resources>
<ListView ItemsSource="{Binding Employees}" ItemTemplate="{StaticResource EmployeeTemplate}" />

在窗口的代码隐藏文件中设置 DataContext

cs 复制代码
public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        EmployeeViewModel viewModel = new EmployeeViewModel();
        DataContext = viewModel;
    }
}

4.5 数据绑定的其他特性

  • 绑定转换器 :当绑定源和绑定目标的类型不匹配时,或者需要对绑定值进行一些转换时,可以使用绑定转换器。绑定转换器是实现了 IValueConverter 接口的类。例如,将一个布尔值转换为字符串显示:
cs 复制代码
public class BooleanToStringConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        if (value is bool boolValue)
        {
            return boolValue ? "Yes" : "No";
        }
        return null;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        if (value is string stringValue)
        {
            return stringValue == "Yes";
        }
        return false;
    }
}

在 XAML 中使用转换器:

XML 复制代码
<Window.Resources>
    <local:BooleanToStringConverter x:Key="BooleanToStringConverter" />
</Window.Resources>
<TextBlock Text="{Binding IsActive, Converter={StaticResource BooleanToStringConverter}}" />
  • 绑定验证 :在用户输入数据时,需要对输入的数据进行验证,确保数据的有效性。WPF 提供了绑定验证机制,可以通过实现 IDataErrorInfo 接口或使用 ValidationRule 类来实现验证。例如,验证一个文本框输入的是否为有效的整数:
cs 复制代码
public class IntegerValidationRule : ValidationRule
{
    public override ValidationResult Validate(object value, CultureInfo cultureInfo)
    {
        if (int.TryParse(value as string, out _))
        {
            return ValidationResult.ValidResult;
        }
        return new ValidationResult(false, "请输入有效的整数。");
    }
}

在 XAML 中应用验证规则:

XML 复制代码
<Window.Resources>
    <local:IntegerValidationRule x:Key="IntegerValidationRule" />
</Window.Resources>
<TextBox>
    <TextBox.Text>
        <Binding Path="Age" UpdateSourceTrigger="PropertyChanged">
            <Binding.ValidationRules>
                <local:IntegerValidationRule />
            </Binding.ValidationRules>
        </Binding>
    </TextBox.Text>
</TextBox>

当用户输入的不是有效的整数时,文本框会显示验证错误信息。

相关推荐
拾2146 分钟前
代码比较功能
学习
数据库知识分享者小北18 分钟前
《阿里云Data+AI:开启数据智能新时代》电子书上线啦!
人工智能·阿里云·云计算
AORO_BEIDOU28 分钟前
防爆手机如何突破“安全与效率“悖论?解析AORO M8的双驱动创新
网络·人工智能·科技·5g·安全·智能手机·信息与通信
不一样的信息安全35 分钟前
两会期间的科技强音:DeepSeek技术引领人工智能新篇章
人工智能
十三画者39 分钟前
【工具】IntelliGenes使用多基因组图谱进行生物标志物发现和预测分析的新型机器学习管道
人工智能·python·机器学习·数据挖掘·数据分析
图扑软件1 小时前
智慧城市新基建!图扑智慧路灯,点亮未来城市生活!
大数据·javascript·人工智能·智慧城市·数字孪生·可视化·智慧路灯
电子科技圈1 小时前
芯科科技推出的BG29超小型低功耗蓝牙®无线SoC,是蓝牙应用的理想之选
人工智能·嵌入式硬件·mcu·物联网·健康医疗·智能硬件·iot
xcLeigh1 小时前
WPF与其他技术的集成:与 WinForms、WCF 等协同工作
c#·wpf·优化
Dm_dotnet1 小时前
使用C#创建一个MCP客户端
人工智能
小君1 小时前
让 Cursor 更加聪明
前端·人工智能·后端