WPF 从入门到实践:基础、ModernUI 与 MVVM 完全指南

WPF 从入门到实践:基础、ModernUI 与 MVVM 完全指南

第一部分:WPF 基础操作(手把手教学)

在这一部分,我们将从零开始创建一个WPF应用程序,逐一学习最常用的控件和布局,并了解每个环节的注意事项。

第1步:创建你的第一个WPF项目

  1. 打开 Visual Studio(推荐 2019 或 2022)。
  2. 选择 创建新项目 → 搜索 WPF → 选择 WPF 应用程序 (.NET Core)WPF 应用程序 (.NET Framework)(推荐 .NET Core/.NET 5/6/7/8,跨平台且性能更好)。
  3. 项目名称输入 WpfDemo,选择保存位置,点击 创建

项目结构简介:

  • App.xaml:应用程序的入口,定义全局资源和启动逻辑。
  • MainWindow.xaml:主窗口的界面设计文件。
  • MainWindow.xaml.cs:主窗口的后台代码文件(通常称为 code-behind)。

注意事项:

  • 如果是 .NET Core 版本,App.xaml 中默认不包含 StartupUri,需要手动添加或修改 Main 方法来指定启动窗口。
  • 建议一开始就熟悉这两个文件的作用,后面会频繁使用。

第2步:认识 XAML 和基本控件

打开 MainWindow.xaml,您会看到类似下面的代码:

xml 复制代码
<Window x:Class="WpfDemo.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">
    <Grid>
        
    </Grid>
</Window>

<Grid> 是一个布局容器,所有控件都要放在布局容器内。

2.1 添加一个文本块(TextBlock)

<Grid> 中添加一个 TextBlock

xml 复制代码
<Grid>
    <TextBlock Text="欢迎学习WPF" 
               HorizontalAlignment="Center" 
               VerticalAlignment="Center" 
               FontSize="20" 
               Foreground="Blue"/>
</Grid>

注意事项:

  • HorizontalAlignmentVerticalAlignment 用于控制控件在容器内的对齐方式。
  • 属性值可以直接写在标签内,也可以使用属性元素语法(复杂对象时使用)。
  • 所有 XAML 元素都必须正确关闭(自关闭或成对关闭)。
2.2 添加一个按钮(Button)并处理点击事件

Grid 中添加一个按钮,并为其添加点击事件:

xml 复制代码
<Button Content="点我" 
        Width="100" Height="30" 
        HorizontalAlignment="Center" 
        VerticalAlignment="Center"
        Click="Button_Click"/>

然后按 F12 或右键点击 Click="Button_Click" 选择"转到定义",Visual Studio 会自动在 MainWindow.xaml.cs 中生成事件处理程序:

csharp 复制代码
private void Button_Click(object sender, RoutedEventArgs e)
{
    MessageBox.Show("按钮被点击了!");
}

注意事项:

  • 事件名称可以任意,但通常采用 控件名_事件名 的命名方式。
  • 在 XAML 中写 Click="Button_Click" 后,编译时会自动检查后台是否有匹配的方法,如果没有会报错。
  • 事件处理程序的方法签名必须匹配委托定义(通常是 object sender, RoutedEventArgs e)。
2.3 文本框(TextBox)和密码框(PasswordBox)

添加一个文本框和一个密码框,并在按钮点击时获取它们的值。

xml 复制代码
<StackPanel VerticalAlignment="Center" HorizontalAlignment="Center">
    <TextBox x:Name="UserNameTextBox" Width="200" Margin="5" Placeholder="请输入用户名"/>
    <PasswordBox x:Name="PasswordBox" Width="200" Margin="5" PasswordChar="*"/>
    <Button Content="登录" Width="100" Margin="5" Click="LoginButton_Click"/>
</StackPanel>

后台代码:

csharp 复制代码
private void LoginButton_Click(object sender, RoutedEventArgs e)
{
    string userName = UserNameTextBox.Text;
    string password = PasswordBox.Password;
    MessageBox.Show($"用户名:{userName},密码:{password}");
}

注意事项:

  • x:Name 属性用于在后台代码中引用该控件。
  • Placeholder 不是 TextBox 的固有属性,WPF 原生不支持占位符文本,但可以通过样式或第三方库实现。上面的 Placeholder 仅为示意,实际需使用 Tag 或附加属性,或者使用 Watermark 控件。
  • PasswordBox.Password 是明文密码,请注意安全性(如果确实需要获取明文)。
2.4 列表控件(ListBox、ComboBox)

添加一个 ListBox 并绑定数据:

xml 复制代码
<ListBox x:Name="FruitListBox" Width="200" Height="100" Margin="5" DisplayMemberPath="Name"/>

在窗口加载时填充数据(MainWindow 构造函数中):

csharp 复制代码
public MainWindow()
{
    InitializeComponent();
    FruitListBox.ItemsSource = new List<Fruit>
    {
        new Fruit { Name = "苹果", Price = 5.5 },
        new Fruit { Name = "香蕉", Price = 3.2 },
        new Fruit { Name = "橙子", Price = 4.8 }
    };
}

public class Fruit
{
    public string Name { get; set; }
    public double Price { get; set; }
}

如果要显示多个属性,可以自定义 ItemTemplate

xml 复制代码
<ListBox x:Name="FruitListBox" Width="200" Height="100" Margin="5">
    <ListBox.ItemTemplate>
        <DataTemplate>
            <StackPanel Orientation="Horizontal">
                <TextBlock Text="{Binding Name}" Width="60"/>
                <TextBlock Text="{Binding Price}" Margin="5,0"/>
            </StackPanel>
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>

注意事项:

  • ItemsSource 可以绑定任何实现了 IEnumerable 的集合。
  • 若要界面随数据变化自动更新,应使用 ObservableCollection<T> 而不是 List<T>
  • DataTemplate 定义了每个列表项的呈现方式,使用 {Binding Path} 绑定数据对象的属性。
2.5 布局容器详解

WPF 提供多种布局面板,掌握它们能灵活设计界面。

  • Grid :表格布局,可定义行和列。

    xml 复制代码
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="100"/>
            <ColumnDefinition Width="*"/>
        </Grid.ColumnDefinitions>
        <TextBlock Grid.Row="0" Grid.Column="0" Text="行0列0"/>
        <TextBlock Grid.Row="0" Grid.Column="1" Text="行0列1"/>
        <TextBlock Grid.Row="1" Grid.ColumnSpan="2" Text="跨两列"/>
    </Grid>
  • StackPanel:水平或垂直堆叠。

  • DockPanel:控件可停靠在上、下、左、右。

  • WrapPanel:自动换行排列。

  • Canvas:绝对定位。

注意事项:

  • 使用 Grid 时,若不指定 RowDefinitionsColumnDefinitions,则默认为单行单列。
  • * 表示按比例分配剩余空间,Auto 表示根据内容自动调整大小。
2.6 数据绑定(基础)

WPF 最强大的特性之一就是数据绑定。让我们创建一个简单的绑定示例。

MainWindow.xaml 中添加一个滑块和一个文本块,使文本块显示滑块的当前值:

xml 复制代码
<StackPanel Margin="10">
    <Slider x:Name="MySlider" Minimum="0" Maximum="100" Value="50"/>
    <TextBlock Text="{Binding ElementName=MySlider, Path=Value}" 
               FontSize="20" HorizontalAlignment="Center"/>
</StackPanel>

这里使用了 ElementName 绑定,将 TextBlock.Text 绑定到 MySlider.Value。移动滑块时,文本自动更新。

注意事项:

  • 绑定的默认模式是 OneWay(单向),但 TextBox.Text 默认是 TwoWay(双向)。
  • 可通过 Mode 属性指定绑定模式:OneTimeOneWayTwoWayOneWayToSource
2.7 样式和资源

使用样式可以统一控件外观。在 App.xaml 或窗口资源中定义样式。

xml 复制代码
<Window.Resources>
    <Style x:Key="MyButtonStyle" TargetType="Button">
        <Setter Property="Background" Value="LightBlue"/>
        <Setter Property="FontSize" Value="14"/>
        <Setter Property="Margin" Value="5"/>
        <Setter Property="Padding" Value="10,5"/>
    </Style>
</Window.Resources>

<Button Content="样式按钮" Style="{StaticResource MyButtonStyle}"/>

注意事项:

  • x:Key 为样式指定唯一键,通过 {StaticResource}{DynamicResource} 引用。
  • 如果不指定 x:Key,样式会自动应用于该类型的所有控件(隐式样式)。

第3步:综合小案例------简易登录界面

将以上知识综合,创建一个简单的登录界面,包含用户名、密码、登录按钮和状态提示。

MainWindow.xaml:

xml 复制代码
<Window x:Class="WpfDemo.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="登录系统" Height="250" Width="300" WindowStartupLocation="CenterScreen">
    <Grid Margin="10">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto"/>
            <ColumnDefinition Width="*"/>
        </Grid.ColumnDefinitions>

        <!-- 用户名 -->
        <Label Grid.Row="0" Grid.Column="0" Content="用户名:" VerticalAlignment="Center"/>
        <TextBox x:Name="UserNameTextBox" Grid.Row="0" Grid.Column="1" Margin="5" Height="25"/>

        <!-- 密码 -->
        <Label Grid.Row="1" Grid.Column="0" Content="密码:" VerticalAlignment="Center"/>
        <PasswordBox x:Name="PasswordBox" Grid.Row="1" Grid.Column="1" Margin="5" Height="25"/>

        <!-- 登录按钮 -->
        <Button x:Name="LoginButton" Grid.Row="2" Grid.ColumnSpan="2" 
                Content="登录" Width="80" Height="30" HorizontalAlignment="Center" 
                Margin="5" Click="LoginButton_Click"/>

        <!-- 状态信息 -->
        <TextBlock x:Name="StatusText" Grid.Row="3" Grid.ColumnSpan="2" 
                   Text="" Foreground="Red" HorizontalAlignment="Center" VerticalAlignment="Center"/>
    </Grid>
</Window>

MainWindow.xaml.cs:

csharp 复制代码
public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
    }

    private void LoginButton_Click(object sender, RoutedEventArgs e)
    {
        string userName = UserNameTextBox.Text;
        string password = PasswordBox.Password;

        // 简单的验证逻辑
        if (userName == "admin" && password == "123456")
        {
            StatusText.Text = "登录成功!";
            StatusText.Foreground = System.Windows.Media.Brushes.Green;
        }
        else
        {
            StatusText.Text = "用户名或密码错误!";
            StatusText.Foreground = System.Windows.Media.Brushes.Red;
        }
    }
}

注意事项:

  • WindowStartupLocation="CenterScreen" 使窗口启动时居中显示。
  • Grid.ColumnSpan="2" 让按钮跨越两列。
  • 这里直接使用 code-behind 处理逻辑,后续 MVVM 部分会重构为更优雅的方式。

第二部分:ModernUI------让界面更现代

2.1 什么是 ModernUI

ModernUI(也称 Fluent Design)是微软为 Windows 应用推荐的现代设计语言,特点是简洁、流畅、富有动感。在 WPF 中,我们可以通过第三方库快速实现这种风格,其中最流行的是 ModernWpfUI(原 MahApps.Metro 的进化版)。

2.2 集成 ModernWpfUI

步骤 1:安装 NuGet 包

在项目中右键"管理 NuGet 程序包",搜索并安装 ModernWpfUI

步骤 2:修改 App.xaml,引入主题资源

xml 复制代码
<Application x:Class="WpfDemo.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             StartupUri="MainWindow.xaml">
    <Application.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <!-- 引入 ModernWpf 主题 -->
                <ResourceDictionary Source="pack://application:,,,/ModernWpf;component/Theme/ThemeResources.xaml"/>
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </Application.Resources>
</Application>

步骤 3:为窗口启用现代样式

修改 MainWindow.xaml

xml 复制代码
<Window x:Class="WpfDemo.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:ui="http://schemas.modernwpf.com/2019"
        ui:WindowHelper.UseModernWindowStyle="True"
        Title="ModernUI 示例" Height="350" Width="500">
    <Grid Margin="10">
        <!-- 这里放置控件,它们会自动获得现代样式 -->
        <StackPanel>
            <TextBox PlaceholderText="请输入内容" Margin="5"/>
            <PasswordBox PlaceholderText="请输入密码" Margin="5"/>
            <Button Content="现代按钮" Style="{StaticResource AccentButtonStyle}" Margin="5"/>
            <CheckBox Content="复选框" Margin="5"/>
            <RadioButton Content="单选" Margin="5"/>
        </StackPanel>
    </Grid>
</Window>

注意事项:

  • ui:WindowHelper.UseModernWindowStyle="True" 启用现代窗口样式,包括圆角、标题栏等。
  • PlaceholderText 是 ModernWpf 为 TextBoxPasswordBox 新增的附加属性,用于显示占位文本。
  • AccentButtonStyle 是预定义的强调按钮样式。

2.3 支持暗色主题

ModernWpfUI 支持自动跟随系统主题或手动切换。在 App.xaml 中添加主题管理器资源:

xml 复制代码
<Application.Resources>
    <ResourceDictionary>
        <ResourceDictionary.MergedDictionaries>
            <ResourceDictionary Source="pack://application:,,,/ModernWpf;component/Theme/ThemeResources.xaml"/>
            <!-- 可选:添加主题管理器 -->
            <ResourceDictionary Source="pack://application:,,,/ModernWpf;component/Theme/ThemeManager.xaml"/>
        </ResourceDictionary.MergedDictionaries>
    </ResourceDictionary>
</Application.Resources>

然后在代码中可以通过 ThemeManager.Current.SetTheme(Theme.Light) 等方式切换主题。

注意事项:

  • 如果手动切换主题,需确保在 App 启动时已加载主题资源。
  • 可以在按钮点击事件中调用 ThemeManager.Current.SetTheme 实现亮/暗切换。

第三部分:MVVM 模式与 Prism 框架

3.1 为什么需要 MVVM

随着业务逻辑复杂化,将大量代码写在 Window 的 code-behind 中会导致:

  • 难以单元测试:UI 元素依赖导致无法单独测试逻辑。
  • 耦合度高:修改界面可能影响逻辑,反之亦然。
  • 代码复用困难:类似逻辑难以在不同 View 中共享。

MVVM 模式通过数据绑定和命令将 View 和 ViewModel 解耦,让开发者专注于业务逻辑。

3.2 MVVM 核心概念

  • View:负责界面呈现,通常使用 XAML 定义,包含控件和绑定。
  • ViewModel :负责界面逻辑和数据状态,实现 INotifyPropertyChanged 接口,以便属性变更时通知 View 更新。
  • Model:数据模型,通常包含业务实体和数据访问层。

3.3 Prism 框架简介

Prism 是一个功能强大的 MVVM 框架,提供以下核心功能:

  • 依赖注入容器(基于 Unity 或 DryIoc)
  • 命令(DelegateCommand)
  • 区域导航(Region)
  • 模块化开发(Module)
  • 对话框服务(DialogService)
  • 事件聚合器(EventAggregator)

3.4 创建第一个 Prism 项目

步骤 1:安装 Prism 模板(可选)

在 Visual Studio 中搜索并安装 Prism Template Pack,可以快速创建 Prism 项目。

步骤 2:手动创建 Prism 项目

创建一个新的 WPF 项目,然后通过 NuGet 安装 Prism.DryIoc(或 Prism.Unity,这里以 DryIoc 为例)。

步骤 3:修改 App.xaml 和 App.xaml.cs

删除 App.xaml 中的 StartupUri,并修改为派生自 PrismApplication

xml 复制代码
<prism:PrismApplication x:Class="WpfDemo.App"
                        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                        xmlns:prism="http://prismlibrary.com/">
    <Application.Resources>
    </Application.Resources>
</prism:PrismApplication>

App.xaml.cs

csharp 复制代码
using System.Windows;
using Prism.DryIoc;
using Prism.Ioc;
using WpfDemo.Views;

namespace WpfDemo
{
    public partial class App : PrismApplication
    {
        protected override Window CreateShell()
        {
            return Container.Resolve<MainWindow>();
        }

        protected override void RegisterTypes(IContainerRegistry containerRegistry)
        {
            // 注册服务和视图
        }
    }
}

3.5 实现一个简单的登录功能(MVVM 方式)

3.5.1 创建 ViewModel

在项目中新建文件夹 ViewModels,添加 MainWindowViewModel.cs

csharp 复制代码
using Prism.Mvvm;
using Prism.Commands;
using System.Windows;

namespace WpfDemo.ViewModels
{
    public class MainWindowViewModel : BindableBase
    {
        private string _userName;
        public string UserName
        {
            get { return _userName; }
            set { SetProperty(ref _userName, value); }
        }

        private string _password;
        public string Password
        {
            get { return _password; }
            set { SetProperty(ref _password, value); }
        }

        private string _statusMessage;
        public string StatusMessage
        {
            get { return _statusMessage; }
            set { SetProperty(ref _statusMessage, value); }
        }

        public DelegateCommand LoginCommand { get; private set; }

        public MainWindowViewModel()
        {
            LoginCommand = new DelegateCommand(ExecuteLogin, CanExecuteLogin);
        }

        private void ExecuteLogin()
        {
            if (UserName == "admin" && Password == "123456")
            {
                StatusMessage = "登录成功!";
            }
            else
            {
                StatusMessage = "用户名或密码错误!";
            }
        }

        private bool CanExecuteLogin()
        {
            return !string.IsNullOrEmpty(UserName) && !string.IsNullOrEmpty(Password);
        }
    }
}
3.5.2 修改 View(MainWindow.xaml)

MainWindowDataContext 设置为 ViewModel(通常在 XAML 中通过 d:DataContext 设计时支持,实际运行时由容器注入):

xml 复制代码
<Window x:Class="WpfDemo.Views.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:prism="http://prismlibrary.com/"
        xmlns:viewModels="clr-namespace:WpfDemo.ViewModels"
        prism:ViewModelLocator.AutoWireViewModel="True"
        Title="Prism MVVM 登录" Height="250" Width="300">
    <Grid Margin="10">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto"/>
            <ColumnDefinition Width="*"/>
        </Grid.ColumnDefinitions>

        <Label Grid.Row="0" Grid.Column="0" Content="用户名:"/>
        <TextBox Grid.Row="0" Grid.Column="1" Text="{Binding UserName, UpdateSourceTrigger=PropertyChanged}" Margin="5"/>

        <Label Grid.Row="1" Grid.Column="0" Content="密码:"/>
        <PasswordBox x:Name="PasswordBox" Grid.Row="1" Grid.Column="1" Margin="5"/>

        <Button Grid.Row="2" Grid.ColumnSpan="2" Content="登录" 
                Command="{Binding LoginCommand}" 
                Width="80" Height="30" HorizontalAlignment="Center" Margin="5"/>

        <TextBlock Grid.Row="3" Grid.ColumnSpan="2" Text="{Binding StatusMessage}" 
                   Foreground="Red" HorizontalAlignment="Center" VerticalAlignment="Center"/>
    </Grid>
</Window>

注意PasswordBox 的密码不能直接绑定,因为 Password 属性不是依赖属性。Prism 提供了附加属性来解决这个问题,或者我们可以在命令执行时手动获取密码。这里我们采用手动方式,修改 ViewModel 和 View:

MainWindow.xaml.cs 中为 PasswordBox 添加一个名称,并在 ViewModel 中添加一个属性来接收密码(通过命令参数传递)。

更好的做法是使用 Prism 的 PasswordBoxHelper 附加属性(需要引入命名空间)。这里为简化,我们直接在后代码中将密码传递给 ViewModel。

修改 View:

xml 复制代码
<PasswordBox x:Name="PasswordBox" Grid.Row="1" Grid.Column="1" Margin="5"/>

修改 LoginCommand 执行时获取密码:

csharp 复制代码
private void ExecuteLogin()
{
    // 如何获取密码?可以在 View 中调用 ViewModel 的方法,但会破坏解耦。
    // 最佳实践:使用 Prism 的 Interaction 或 Behavior,或者使用附加属性。
    // 简单起见,我们可以在 View 的 code-behind 中处理按钮点击,并调用 ViewModel 的方法。
}

为了保持纯净的 MVVM,我们使用 Prism 的 PasswordBoxHelper(需要安装 Prism.Wpf 包):

在 XAML 中添加命名空间:

xml 复制代码
xmlns:prism="http://prismlibrary.com/"

PasswordBox 添加附加属性:

xml 复制代码
<PasswordBox prism:PasswordBoxHelper.Password="{Binding Password, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />

然后 ViewModel 中的 Password 属性就可以自动获取输入了。

注意事项:

  • ViewModelLocator.AutoWireViewModel="True" 会自动根据命名规则找到对应的 ViewModel(View 同名且位于 ViewModels 文件夹下)。
  • 绑定命令时,CanExecute 会自动触发界面更新(例如按钮的可用性),无需手动调用。

3.6 使用对话框服务

Prism 提供了 IDialogService 用于显示对话框,解耦 View 和 ViewModel。

3.6.1 注册对话框

App.RegisterTypes 中注册对话框:

csharp 复制代码
protected override void RegisterTypes(IContainerRegistry containerRegistry)
{
    containerRegistry.RegisterDialog<NotificationDialog, NotificationDialogViewModel>();
}
3.6.2 创建对话框 View 和 ViewModel

添加一个用户控件 NotificationDialog.xaml 作为对话框内容:

xml 复制代码
<UserControl x:Class="WpfDemo.Views.NotificationDialog"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             Width="300" Height="200">
    <Grid>
        <TextBlock Text="{Binding Message}" HorizontalAlignment="Center" VerticalAlignment="Center"/>
    </Grid>
</UserControl>

添加 ViewModel NotificationDialogViewModel.cs

csharp 复制代码
using Prism.Mvvm;
using Prism.Services.Dialogs;
using System;

namespace WpfDemo.ViewModels
{
    public class NotificationDialogViewModel : BindableBase, IDialogAware
    {
        private string _message;
        public string Message
        {
            get { return _message; }
            set { SetProperty(ref _message, value); }
        }

        public string Title => "提示";

        public event Action<IDialogResult> RequestClose;

        public bool CanCloseDialog() => true;

        public void OnDialogClosed() { }

        public void OnDialogOpened(IDialogParameters parameters)
        {
            Message = parameters.GetValue<string>("message");
        }
    }
}
3.6.3 在 ViewModel 中使用对话框

修改 MainWindowViewModel,注入 IDialogService

csharp 复制代码
private readonly IDialogService _dialogService;

public MainWindowViewModel(IDialogService dialogService)
{
    _dialogService = dialogService;
    LoginCommand = new DelegateCommand(ExecuteLogin, CanExecuteLogin);
}

private void ExecuteLogin()
{
    if (UserName == "admin" && Password == "123456")
    {
        _dialogService.ShowDialog("NotificationDialog", new DialogParameters($"message=登录成功"), r => { });
    }
    else
    {
        _dialogService.ShowDialog("NotificationDialog", new DialogParameters($"message=用户名或密码错误"), r => { });
    }
}

注意事项:

  • IDialogService 通过构造函数注入,由 Prism 容器自动提供。
  • DialogParameters 用于传递参数给对话框。

第四部分:注意事项与学习资源

4.1 开发注意事项总结

  1. 布局优先:在写界面之前,先用布局容器规划好结构,避免绝对定位导致界面缩放问题。
  2. 命名规范 :为控件起有意义的名字(如 UserNameTextBox),便于维护。
  3. 资源管理:将样式、模板、转换器等放入资源字典,提高复用性。
  4. 数据绑定:尽量使用绑定而不是在 code-behind 中直接操作控件。
  5. 异步处理 :涉及耗时操作(如网络请求)时,使用异步命令(DelegateCommand 支持异步委托)。
  6. 异常处理:在 ViewModel 中添加异常捕获,避免程序崩溃。
  7. 性能优化 :虚拟化长列表,减少 UI 元素数量;使用 ObservableCollection 时注意不要频繁更新整个集合。
  8. MVVM 纯度 :避免在 ViewModel 中引用任何 View 类型(如 MessageBox),使用服务代替。

4.2 官方与社区资源

  • Microsoft 官方文档WPF .NET 文档 最权威的基础知识来源。

  • Prism 官方文档Prism Library 详细介绍了 Prism 的各个模块。

  • ModernWpfUI GitHubModernWpfUI 查看源码和示例。

  • 视频教程:B 站搜索"WPF 入门"或"Prism 教程",有很多免费视频。

  • 书籍推荐:《深入浅出 WPF》(刘铁锰)、《Prism 框架开发实战》。


通过以上一步步的学习,您应该已经掌握了 WPF 的基础开发、ModernUI 的集成以及 MVVM/Prism 的核心用法。继续动手实践,多写多练,您将能构建出专业、现代化的桌面应用程序。

相关推荐
夏霞17 小时前
c# signlar 客户端传递参数给服务端配置方法
开发语言·c#
武藤一雄17 小时前
从零构建C# OOP 知识体系
windows·microsoft·c#·.net·.netcore·oop
唐青枫18 小时前
C#.NET ConcurrentStack<T> 深入解析:无锁栈原理、LIFO 语义与使用边界
c#·.net
aini_lovee20 小时前
C# 实现邮件发送源码(支持附件)
开发语言·javascript·c#
WarrenMondeville1 天前
1.Unity面向对象-单一职责原则
unity·设计模式·c#
寒风暖哥1 天前
Oracle视图查询返回空数据集的分析
oracle·c#
万兴丶1 天前
Unity用C#完成抖音小游戏接入引力引擎(Gravity Engine)完整指南,一篇文章讲清楚!
unity·c#·游戏引擎·抖音
福赖1 天前
《C#反射机制》
开发语言·c#
向上的车轮1 天前
熟悉C#如何转TypeScript?
开发语言·typescript·c#
我是唐青枫1 天前
C#.NET ReaderWriterLockSlim 深入解析:读写锁原理、升级锁与使用边界
开发语言·c#·.net