Loading

WPF常用 NuGet 包的作用和用途

1. Microsoft.Extensions.DependencyInjection

依赖注入(DI)容器

  • 核心功能:提供依赖注入服务容器,管理对象的创建和生命周期
  • 主要用途
    • 注册和解析服务(服务、视图模型、仓储等)
    • 管理对象生命周期(Singleton、Scoped、Transient)
    • 实现松耦合架构

典型使用

// 在 App.xaml.cs 中配置服务
var services = new ServiceCollection();

// 注册服务
services.AddSingleton<IDataService, DataService>();
services.AddTransient<MainViewModel>();
services.AddScoped<IRepository, Repository>();

var serviceProvider = services.BuildServiceProvider();

// 获取服务
var viewModel = serviceProvider.GetRequiredService<MainViewModel>();

生命周期

  • Singleton:整个应用程序生命周期内只创建一次
  • Transient:每次请求都创建新实例
  • Scoped:在作用域内是单例(WPF 中较少用)

2. Microsoft.Extensions.Hosting

通用主机构建器

  • 核心功能:提供应用程序主机框架,用于配置和管理应用程序生命周期
  • 主要用途
    • 统一的应用程序启动和配置模式
    • 集成依赖注入
    • 配置管理(appsettings.json)
    • 日志记录
    • 后台服务支持

典型使用

// App.xaml.cs
public partial class App : Application
{
    private readonly IHost _host;

    public App()
    {
        _host = Host.CreateDefaultBuilder()
            .ConfigureServices((context, services) =>
            {
                // 注册服务
                services.AddSingleton<MainWindow>();
                services.AddSingleton<IDataService, DataService>();
                services.AddTransient<MainViewModel>();
                
                // 配置
                services.Configure<AppSettings>(
                    context.Configuration.GetSection("AppSettings"));
            })
            .ConfigureLogging(logging =>
            {
                logging.AddDebug();
                logging.AddConsole();
            })
            .Build();
    }

    protected override async void OnStartup(StartupEventArgs e)
    {
        await _host.StartAsync();
        
        var mainWindow = _host.Services.GetRequiredService<MainWindow>();
        mainWindow.Show();
        
        base.OnStartup(e);
    }

    protected override async void OnExit(ExitEventArgs e)
    {
        await _host.StopAsync();
        _host.Dispose();
        base.OnExit(e);
    }
}

主要优势

  • 标准化的配置模式
  • 内置日志和配置系统
  • 便于测试和维护

3. Microsoft.Xaml.Behaviors.Wpf

XAML 行为库(原 Blend SDK)

  • 核心功能:在 XAML 中以声明式方式添加交互行为,无需代码后置
  • 主要用途
    • 事件到命令的绑定
    • 触发器和行为
    • 实现 MVVM 模式中的交互逻辑

常用组件

a) EventTrigger + InvokeCommandAction(事件绑定命令)

<Window xmlns:i="http://schemas.microsoft.com/xaml/behaviors">
    <i:Interaction.Triggers>
        <i:EventTrigger EventName="Loaded">
            <i:InvokeCommandAction Command="{Binding LoadedCommand}"/>
        </i:EventTrigger>
    </i:Interaction.Triggers>
    
    <Button Content="点击">
        <i:Interaction.Triggers>
            <i:EventTrigger EventName="MouseEnter">
                <i:InvokeCommandAction Command="{Binding MouseEnterCommand}"/>
            </i:EventTrigger>
        </i:Interaction.Triggers>
    </Button>
</Window>

b) 自定义 Behavior

public class TextBoxEnterKeyBehavior : Behavior<TextBox>
{
    public ICommand Command { get; set; }

    protected override void OnAttached()
    {
        AssociatedObject.KeyDown += OnKeyDown;
    }

    protected override void OnDetaching()
    {
        AssociatedObject.KeyDown -= OnKeyDown;
    }

    private void OnKeyDown(object sender, KeyEventArgs e)
    {
        if (e.Key == Key.Enter && Command?.CanExecute(null) == true)
        {
            Command.Execute(null);
        }
    }
}

4. CommunityToolkit.Mvvm

MVVM 工具包(原 MVVM Toolkit / MVVMLight 的继任者)

  • 核心功能:提供 MVVM 模式开发的辅助类和源生成器
  • 主要用途
    • 简化 ViewModel 开发
    • 属性变更通知
    • 命令实现
    • 消息传递

核心功能详解

a) ObservableObject(属性变更通知)

// 传统方式
public class MainViewModel : INotifyPropertyChanged
{
    private string _name;
    public string Name
    {
        get => _name;
        set
        {
            _name = value;
            OnPropertyChanged(nameof(Name));
        }
    }
}

// 使用 CommunityToolkit.Mvvm
public partial class MainViewModel : ObservableObject
{
    [ObservableProperty]
    private string name;  // 自动生成 Name 属性和通知
}

b) RelayCommand(命令实现)

public partial class MainViewModel : ObservableObject
{
    // 源生成器自动生成 SaveCommand
    [RelayCommand]
    private void Save()
    {
        // 保存逻辑
    }

    // 带参数的命令
    [RelayCommand]
    private void Delete(string id)
    {
        // 删除逻辑
    }

    // 带 CanExecute 的命令
    [RelayCommand(CanExecute = nameof(CanSave))]
    private async Task SaveAsync()
    {
        await Task.Delay(1000);
    }

    private bool CanSave() => !string.IsNullOrEmpty(Name);
}

c) Messenger(消息传递)

// 定义消息
public class UserLoginMessage
{
    public string UserName { get; set; }
}

// 发送消息
WeakReferenceMessenger.Default.Send(new UserLoginMessage 
{ 
    UserName = "张三" 
});

// 接收消息
public partial class MainViewModel : ObservableObject, 
    IRecipient<UserLoginMessage>
{
    public MainViewModel()
    {
        WeakReferenceMessenger.Default.Register(this);
    }

    public void Receive(UserLoginMessage message)
    {
        // 处理消息
        StatusText = $"用户 {message.UserName} 已登录";
    }
}

d) 其他特性

// 属性变更通知其他属性
[ObservableProperty]
[NotifyPropertyChangedFor(nameof(FullName))]
private string firstName;

[ObservableProperty]
[NotifyPropertyChangedFor(nameof(FullName))]
private string lastName;

public string FullName => $"{FirstName} {LastName}";

// 属性变更时通知命令
[ObservableProperty]
[NotifyCanExecuteChangedFor(nameof(SaveCommand))]
private string name;

组合使用示例

完整的现代 WPF 应用架构:

// App.xaml.cs
public partial class App : Application
{
    private readonly IHost _host;

    public App()
    {
        _host = Host.CreateDefaultBuilder()
            .ConfigureServices((context, services) =>
            {
                // 注册窗口和视图
                services.AddSingleton<MainWindow>();
                services.AddTransient<SettingsWindow>();
                
                // 注册 ViewModel
                services.AddSingleton<MainViewModel>();
                services.AddTransient<SettingsViewModel>();
                
                // 注册服务
                services.AddSingleton<IDataService, DataService>();
                services.AddHttpClient<IApiService, ApiService>();
            })
            .Build();
    }

    protected override async void OnStartup(StartupEventArgs e)
    {
        await _host.StartAsync();
        
        var mainWindow = _host.Services.GetRequiredService<MainWindow>();
        mainWindow.DataContext = _host.Services.GetRequiredService<MainViewModel>();
        mainWindow.Show();
        
        base.OnStartup(e);
    }
}

// MainViewModel.cs
public partial class MainViewModel : ObservableObject
{
    private readonly IDataService _dataService;

    public MainViewModel(IDataService dataService)
    {
        _dataService = dataService;
    }

    [ObservableProperty]
    private string searchText;

    [ObservableProperty]
    private ObservableCollection<User> users;

    [RelayCommand]
    private async Task LoadDataAsync()
    {
        Users = await _dataService.GetUsersAsync();
    }

    [RelayCommand(CanExecute = nameof(CanSearch))]
    private void Search()
    {
        // 搜索逻辑
    }

    private bool CanSearch() => !string.IsNullOrEmpty(SearchText);
}

// MainWindow.xaml
<Window xmlns:i="http://schemas.microsoft.com/xaml/behaviors">
    <i:Interaction.Triggers>
        <i:EventTrigger EventName="Loaded">
            <i:InvokeCommandAction Command="{Binding LoadDataCommand}"/>
        </i:EventTrigger>
    </i:Interaction.Triggers>
    
    <Grid>
        <TextBox Text="{Binding SearchText, UpdateSourceTrigger=PropertyChanged}"/>
        <Button Command="{Binding SearchCommand}" Content="搜索"/>
    </Grid>
</Window>

总结对比

包名 主要作用 使用场景
Microsoft.Extensions.DependencyInjection 依赖注入容器 服务注册与解析
Microsoft.Extensions.Hosting 应用主机框架 应用启动、配置、日志
Microsoft.Xaml.Behaviors.Wpf XAML 行为库 事件绑定命令、自定义行为
CommunityToolkit.Mvvm MVVM 工具包 简化 ViewModel 开发

这四个包组合使用,可以构建出结构清晰、易于维护的现代 WPF 应用程序!

posted @ 2026-02-07 15:55  老卫同学  阅读(9)  评论(0)    收藏  举报