csharp:wpf基本语法

这是本文档旧的修订版!


WPF MVVM 标准示例教程

理解 WPF 的核心就在于理解 MVVM (Model-View-ViewModel) 模式。

在这个例子中,我们将创建一个简单的 “用户列表管理” 应用。

  • 功能:输入姓名和年龄,点击添加按钮,列表会实时更新。
  • 特点:完全不使用传统的事件处理器(如 `Button_Click`),而是使用 数据绑定 (Data Binding)命令 (Command)

在标准的 MVVM 中,我们需要两个辅助类:

  1. ViewModelBase: 实现 `INotifyPropertyChanged` 接口,用于通知 UI 数据变了。
  2. RelayCommand: 实现 `ICommand` 接口,用于处理按钮点击逻辑。
using System;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Windows.Input;
 
namespace WpfMvvmExample
{
    // 1. 通知基类:当属性变化时,告诉 UI 刷新
    public class ViewModelBase : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
 
        protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
 
        // 辅助方法:设置值并通知
        protected bool SetProperty<T>(ref T field, T value, [CallerMemberName] string propertyName = null)
        {
            if (Equals(field, value)) return false;
            field = value;
            OnPropertyChanged(propertyName);
            return true;
        }
    }
 
    // 2. 命令类:将按钮点击行为绑定到方法
    public class RelayCommand : ICommand
    {
        private readonly Action<object> _execute;
        private readonly Predicate<object> _canExecute;
 
        public RelayCommand(Action<object> execute, Predicate<object> canExecute = null)
        {
            _execute = execute;
            _canExecute = canExecute;
        }
 
        public bool CanExecute(object parameter) => _canExecute == null || _canExecute(parameter);
 
        public void Execute(object parameter) => _execute(parameter);
 
        public event EventHandler CanExecuteChanged
        {
            add { CommandManager.RequerySuggested += value; }
            remove { CommandManager.RequerySuggested -= value; }
        }
    }
}

这是纯粹的数据对象,不包含任何 UI 逻辑。

namespace WpfMvvmExample
{
    public class User
    {
        public string Name { get; set; }
        public int Age { get; set; }
 
        // 用于显示的格式化字符串
        public string DisplayInfo => $"{Name} ({Age}岁)";
    }
}

这是 MVVM 的核心。它是 View(界面)和 Model(数据)的桥梁。

  • 它持有数据列表 (`ObservableCollection`)。
  • 它持有当前输入的字段。
  • 它持有命令 (`AddUserCommand`)。
using System.Collections.ObjectModel;
using System.Windows;
 
namespace WpfMvvmExample
{
    public class MainViewModel : ViewModelBase
    {
        // --- 状态字段 ---
        private string _inputName;
        private int _inputAge;
 
        // --- 绑定到界面的属性 ---
        public string InputName
        {
            get => _inputName;
            set => SetProperty(ref _inputName, value); // 值改变时通知 UI
        }
 
        public int InputAge
        {
            get => _inputAge;
            set => SetProperty(ref _inputAge, value);
        }
 
        // ObservableCollection 是 WPF 列表绑定的神器,集合变动会自动刷新界面
        public ObservableCollection<User> Users { get; set; }
 
        // --- 命令 ---
        public RelayCommand AddUserCommand { get; set; }
 
        // --- 构造函数 ---
        public MainViewModel()
        {
            Users = new ObservableCollection<User>
            {
                new User { Name = "张三", Age = 25 } // 初始数据
            };
 
            // 初始化命令:指定执行逻辑(AddUser) 和 判断逻辑(CanAddUser)
            AddUserCommand = new RelayCommand(AddUser, CanAddUser);
        }
 
        // --- 逻辑方法 ---
        private void AddUser(object obj)
        {
            // 添加到集合
            Users.Add(new User { Name = InputName, Age = InputAge });
 
            // 清空输入框
            InputName = string.Empty;
            InputAge = 0;
        }
 
        // 判断按钮是否可用(例如:名字不能为空)
        // 如果返回 false,WPF 会自动禁用按钮
        private bool CanAddUser(object obj)
        {
            return !string.IsNullOrWhiteSpace(InputName);
        }
    }
}

在 XAML 中,我们不写任何 C# 代码来处理逻辑,全部通过 `Binding` 连接到 ViewModel。

<Window x:Class="WpfMvvmExample.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:WpfMvvmExample"
        mc:Ignorable="d"
        Title="MVVM 标准示例" Height="350" Width="400">
 
    <Grid Margin="20">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>
 
        <!-- 输入区域 -->
        <StackPanel Grid.Row="0" Orientation="Horizontal" Margin="0,0,0,10">
            <TextBlock Text="姓名:" VerticalAlignment="Center"/>
            <!-- UpdateSourceTrigger=PropertyChanged 表示每敲一个字都同步给 ViewModel -->
            <TextBox Text="{Binding InputName, UpdateSourceTrigger=PropertyChanged}" 
                     Width="100" Margin="5,0"/>
 
            <TextBlock Text="年龄:" VerticalAlignment="Center" Margin="10,0,0,0"/>
            <TextBox Text="{Binding InputAge, UpdateSourceTrigger=PropertyChanged}" 
                     Width="50" Margin="5,0"/>
        </StackPanel>
 
        <!-- 按钮区域 -->
        <!-- Command 绑定到 ViewModel 中的 AddUserCommand -->
        <Button Grid.Row="1" Content="添加用户" 
                Command="{Binding AddUserCommand}"
                Width="100" HorizontalAlignment="Left" Margin="0,0,0,10"/>
 
        <!-- 列表区域 -->
        <!-- ItemsSource 绑定到 Users 集合 -->
        <ListBox Grid.Row="2" ItemsSource="{Binding Users}">
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <!-- 显示 User 对象的 DisplayInfo 属性 -->
                    <TextBlock Text="{Binding DisplayInfo}" FontSize="14"/>
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>
    </Grid>
</Window>

最后,我们需要把 View 和 ViewModel 连接起来。这通常在 `MainWindow.xaml.cs` 中完成。

using System.Windows;
 
namespace WpfMvvmExample
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
 
            // 关键步骤:设置 DataContext
            // 这告诉 View:“你的数据源和逻辑都在 MainViewModel 里”
            this.DataContext = new MainViewModel();
        }
    }
}
  1. DataContext (数据上下文):
    • 在 `MainWindow.xaml.cs` 中,我们把 `MainViewModel` 赋值给了 `DataContext`。
    • 这使得 XAML 中的 `{Binding InputName}` 知道去 `MainViewModel` 里找 `InputName` 属性。
  1. INotifyPropertyChanged:
    • 当你在输入框打字时,`set` 访问器被调用,`OnPropertyChanged` 被触发。
    • WPF 界面收到通知,知道数据变了。
  1. ICommand (命令):
    • 注意 XAML 中的 `<Button Command=“{Binding AddUserCommand}” … />`。
    • WPF 会自动调用 `AddUserCommand.Execute` 来运行逻辑。
    • WPF 还会自动调用 `AddUserCommand.CanExecute`。如果我们在 `CanAddUser` 方法里返回 `false`(比如名字为空),按钮会自动变灰(禁用)
  1. ObservableCollection:
    • 普通的 `List<T>` 添加数据时,界面不会知道。
    • `ObservableCollection<T>` 在添加/删除元素时会发出通知,列表控件(ListBox)会自动刷新显示新数据。

该主题尚不存在

您访问的页面并不存在。如果允许,您可以使用创建该页面按钮来创建它。

  • csharp/wpf基本语法.1764142847.txt.gz
  • 最后更改: 2025/11/26 15:40
  • 张叶安