目录

C-WPF-基础知识学习三

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

https://i-blog.csdnimg.cn/direct/2d5bb260b23345aca1221e45131e57c2.png

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

  • 声明式编程 :通过 XAML(可扩展应用程序标记语言),开发者可以以声明的方式定义界面,将界面设计与业务逻辑分离,提高开发效率和可维护性。
  • 强大的图形渲染 :基于 DirectX 技术,WPF 能够实现高质量的 2D 和 3D 图形渲染,支持硬件加速,确保复杂图形和动画的流畅显示。
  • 数据绑定 :提供了强大的数据绑定机制,使得 UI 元素能够自动反映数据源的变化,并且可以双向绑定,方便数据的交互和更新。
  • 样式和模板 :允许开发者定义统一的样式和模板,实现界面的一致性和复用性,同时可以轻松地定制控件的外观和行为。
  • 动画支持 :内置了丰富的动画系统,包括线性动画、关键帧动画等,能够创建出生动的用户界面。
  • 企业级应用 :如办公软件、数据分析工具等,需要提供复杂的界面和交互功能,WPF 可以满足这些需求。
  • 多媒体应用 :视频播放器、音频编辑软件等,利用 WPF 的图形和多媒体处理能力,实现高质量的媒体播放和编辑功能。
  • 游戏开发 :虽然不是主流的游戏开发平台,但 WPF 可以用于开发一些小型的 2D 游戏,尤其是需要精美的界面和动画效果的游戏。

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

  1. 打开 Visual Studio,选择 “创建新项目”。
  2. 在搜索框中输入 “WPF 应用”,选择适合的项目模板,如 “WPF 应用(.NET Framework)” 或 “WPF 应用(.NET Core)”,根据自己的需求选择。
  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 是一种基于 XML 的标记语言,用于描述 WPF 应用程序的用户界面。它通过标签和属性的方式来定义界面元素的结构和外观,使得界面设计更加直观和易于理解。

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

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

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

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

  • 命名空间 :XAML 使用命名空间来引用不同的类型。在每个 XAML 文件的根元素中,通常会定义默认命名空间和其他需要的命名空间。例如:
<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 用于指定代码隐藏文件中对应的类。

  • 布局容器
    • Grid :将界面划分为行和列的网格,子元素可以通过 Grid.RowGrid.Column 附加属性指定在网格中的位置。例如:
<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 属性可以设置排列方向,默认是垂直方向。例如:
<StackPanel Orientation="Horizontal">
    <Button Content="Button 1" />
    <Button Content="Button 2" />
    <Button Content="Button 3" />
</StackPanel>
  • WrapPanel :子元素会按照指定的方向依次排列,当一行或一列排满时,会自动换行或换列。例如:
<WrapPanel>
    <Button Content="Short Button" />
    <Button Content="A Longer Button" />
    <Button Content="Another Button" />
</WrapPanel>
  • DockPanel :子元素可以停靠在面板的边缘,通过 DockPanel.Dock 附加属性设置停靠位置。例如:
<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 事件处理按钮的点击操作。
<Button Content="Submit" Click="Button_Click" />

在后台代码中:

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

后台代码:

private void TextBox_TextChanged(object sender, TextChangedEventArgs e)
{
    TextBox textBox = (TextBox)sender;
    string text = textBox.Text;
    // 处理文本变化逻辑
}
  • ComboBox :下拉列表框,用户可以从预定义的选项中选择一个值。通过 ItemsSource 属性绑定数据源,通过 SelectedItemSelectedValue 属性获取当前选中的项。
<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 事件响应状态变化。
<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 属性判断是否被选中。
<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 属性值与单选按钮的选中状态进行转换。

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

  • OneWay :数据从绑定源流向绑定目标,当绑定源属性值发生变化时,绑定目标属性会自动更新,但绑定目标的变化不会影响绑定源。常用于显示只读数据的场景,如显示数据库中的记录。
<TextBlock Text="{Binding ReadOnlyProperty, Mode=OneWay}" />
  • TwoWay :数据在绑定源和绑定目标之间双向流动,当绑定源属性值变化时,绑定目标更新;当绑定目标属性值变化时,绑定源也会相应更新。常用于需要用户输入并更新数据的场景,如编辑表单。
<TextBox Text="{Binding EditableProperty, Mode=TwoWay}" />
  • OneTime :数据在初始化时从绑定源流向绑定目标,之后绑定源的变化不会再影响绑定目标。适用于数据在应用程序运行过程中不会改变的情况,如显示应用程序的版本号。
<TextBlock Text="{Binding AppVersion, Mode=OneTime}" />
  • 创建数据源 :通常会创建一个 ViewModel 类来作为数据源。ViewModel 类应该实现 INotifyPropertyChanged 接口,以便在属性值发生变化时通知绑定目标更新。例如:
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 中的绑定就可以找到对应的数据源。
public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        UserViewModel viewModel = new UserViewModel();
        DataContext = viewModel;
    }
}
  • 在 XAML 中进行绑定 :使用 Binding 标记扩展将 UI 元素的属性绑定到 ViewModel 的属性上。
<TextBox Text="{Binding Name}" />

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

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

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 中:

<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

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        EmployeeViewModel viewModel = new EmployeeViewModel();
        DataContext = viewModel;
    }
}
  • 绑定转换器 :当绑定源和绑定目标的类型不匹配时,或者需要对绑定值进行一些转换时,可以使用绑定转换器。绑定转换器是实现了 IValueConverter 接口的类。例如,将一个布尔值转换为字符串显示:
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 中使用转换器:

<Window.Resources>
    <local:BooleanToStringConverter x:Key="BooleanToStringConverter" />
</Window.Resources>
<TextBlock Text="{Binding IsActive, Converter={StaticResource BooleanToStringConverter}}" />
  • 绑定验证 :在用户输入数据时,需要对输入的数据进行验证,确保数据的有效性。WPF 提供了绑定验证机制,可以通过实现 IDataErrorInfo 接口或使用 ValidationRule 类来实现验证。例如,验证一个文本框输入的是否为有效的整数:
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 中应用验证规则:

<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>

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