WPF/C#:使用Stylet中的IWindowManager用于显示等待窗体、对话框与消息框

前言

显示等待框意义

在创建WPF应用的时候,如果我们要执行一个耗时的操作,那么给用户显示一个等待窗体是很常见的需求,通过显示一个等待窗体让用户明白运行的这个软件并没有崩溃,能有效消除用户的焦虑与不确定性,同时能极大提升用户体验,展示软件的专业性和品质,将无聊的等待转化为可预期的、安心的过程。

显示对话框意义

对话框能有效地捕获用户焦点。作为模态窗口,它会强制用户必须完成当前任务(如确认、输入信息或做出选择),之后才能继续操作主窗口。这保证了关键业务流程(如保存文件前的确认)的完整性,防止用户误操作。其次,对话框是信息收集与展示的专用容器。它将特定任务(如设置、登录、详情查看)的UI元素和逻辑封装起来,使主窗口界面保持简洁,同时提升了代码的模块化和可维护性。

显示信息框意义

信息框的核心价值在于即时性与强制性。对于操作成功、失败或出现警告等重要反馈,它能立刻捕获用户注意力,通过模态显示确保用户看到并处理该信息,避免了关键提示被忽略。其次,它为用户提供了快速决策的途径。除了纯信息展示,信息框可附带“是/否”、“确定/取消”等按钮,让用户在不离开当前上下文的情况下,就能对简单询问做出迅速回应,如确认删除操作。

Stylet介绍

Stylet是一个轻量级、高性能的MVVM框架,专为WPF设计。它摆脱了传统MVVM的样板代码,通过基于约定的特性,使得View和ViewModel的自动关联、依赖注入等变得极其简单。开发者几乎无需配置即可快速上手,其内置的功能如IConductor屏幕管理和事件聚合器,能优雅地处理复杂的应用程序导航与模块间通信。Stylet的目标是让开发者专注于业务逻辑本身,而非繁琐的框架配置,从而显著提升WPF应用的开发效率与代码质量。

本文通过使用Stylet内置的IWindowManager可以很容易实现这个需求。

显示等待框

要显示等待窗体那么必须先做一个等待窗体。

创建一个WaitingView.xaml:

<Window x:Class="Rouyan.Pages.View.WaitingView"         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:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"         xmlns:local="clr-namespace:Rouyan.Pages.View"         mc:Ignorable="d"         Title="WaitingWindow"          Height="200"          Width="350"         WindowStyle="ToolWindow"         WindowStartupLocation="CenterScreen"         ResizeMode="NoResize"         Topmost="True">     <Grid>         <Grid.RowDefinitions>             <RowDefinition Height="Auto"/>             <RowDefinition Height="Auto"/>         </Grid.RowDefinitions>                  <Border Grid.Row="0"                 Background="{DynamicResource PrimaryHueMidBrush}"                 Padding="16 8">             <TextBlock HorizontalAlignment="Center"                        Text="{Binding Text}"                        FontSize="16"/>         </Border>                  <!-- 进度条区域 -->         <StackPanel Grid.Row="1"                     Orientation="Vertical"                     HorizontalAlignment="Center"                     VerticalAlignment="Center"                     Margin="20">                          <ProgressBar Style="{StaticResource MaterialDesignCircularProgressBar}"                          Foreground="{DynamicResource SecondaryHueMidBrush}"                          Width="60"                          Height="60"                          IsIndeterminate="True"/>                              <TextBlock Text="请稍候..."                        FontSize="14"                        HorizontalAlignment="Center"                        Foreground="{DynamicResource MaterialDesignBody}"                        Margin="0,10,0,0"/>                          </StackPanel>     </Grid> </Window> 

效果:

WPF/C#:使用Stylet中的IWindowManager用于显示等待窗体、对话框与消息框

分为两行,上面一行用于显示要显示的信息,下面一行用于显示ProgressBar与"请稍候..."的组合。

现在再来创建对应的ViewModel:

 public class WaitingViewModel : Screen  {            public string Text { get; set; } = "处理中...";   } 

显示这个等待窗体,比如当我们运行一个耗时任务的时候,可以先显示这个等待窗体给用户:

 // 显示等待窗体            waitingVm = _container.Get<WaitingViewModel>();  waitingVm.Text = "正在分析请求,请稍候...";  _windowManager.ShowWindow(waitingVm); 

显示等待窗体主要使用了Stylet中自带的一个组件IWindowManager,我们可以在构造函数中进行依赖注入:

private readonly IContainer _container; private readonly IWindowManager _windowManager;  public TerminalAgentViewModel(IContainer container,IWindowManager windowManager) {     _container = container;     _windowManager = windowManager; } 

由于等待窗体是一个Window,因此需要使用IWindowManager的ShowWindow方法。

Stylet会帮我们将所有View与ViewModel都以瞬态的形式注入依赖注入容器中了,因此可以不用自己在这里new一个viewmodel而是可以直接从容器中取一个出来:

 waitingVm = _container.Get<WaitingViewModel>(); 

IWindowManager的ShowWindow方法的使用,反直觉的一点是传入的不是这个窗体,而是这个窗体对应的ViewModel,Stylet会根据这个ViewModel自动找到对应的View,这也体现了Stylet中ViewModel First的思想。

效果:

WPF/C#:使用Stylet中的IWindowManager用于显示等待窗体、对话框与消息框

这时候可能会有一个疑问就是那么怎么关闭这个窗体呢?

如果是获取对应的Window,我们调用close方法就可以了,现在获取的是对应的ViewModel该如何关闭这个窗体呢?

Stylet已经考虑到了这一个,只要这样写就可以关闭这个窗体:

 waitingVm.RequestClose(); 

显示对话框

使用Stylet中的IWindowManager显示对话框同样也很简单。

首先创建一个HumanApprovalDialogView:

<Window x:Class="Rouyan.Pages.View.HumanApprovalDialogView"         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:s="https://github.com/canton7/Stylet"         mc:Ignorable="d"         Title="{Binding Title}"         Height="200"         Width="420"         WindowStartupLocation="CenterOwner"         ResizeMode="NoResize"         Topmost="True">     <Window.InputBindings>         <KeyBinding Command="{s:Action Approve}" Key="Y"/>         <KeyBinding Command="{s:Action Reject}" Key="N"/>     </Window.InputBindings>     <Grid Margin="16">         <Grid.RowDefinitions>             <RowDefinition Height="*"/>             <RowDefinition Height="Auto"/>         </Grid.RowDefinitions>          <!-- 顶部消息行 -->         <ScrollViewer Grid.Row="0" VerticalScrollBarVisibility="Auto">             <TextBlock Text="{Binding Message}"                        TextWrapping="Wrap"                        FontSize="14"/>         </ScrollViewer>          <!-- 底部按钮行:左侧同意,右侧拒绝 -->         <Grid Grid.Row="1" Margin="0,16,0,0">             <Grid.ColumnDefinitions>                 <ColumnDefinition Width="*"/>                 <ColumnDefinition Width="*"/>             </Grid.ColumnDefinitions>              <Button Grid.Column="0"                     Content="同意(Y)"                     Width="100"                     Height="30"                     HorizontalAlignment="Left"                     IsDefault="True"                     Command="{s:Action Approve}"/>              <Button Grid.Column="1"                     Content="拒绝(N)"                     Width="100"                     Height="30"                     HorizontalAlignment="Right"                     IsCancel="True"                     Command="{s:Action Reject}"/>         </Grid>     </Grid> </Window> 

效果:

WPF/C#:使用Stylet中的IWindowManager用于显示等待窗体、对话框与消息框

创建对应的ViewModel:

public class HumanApprovalDialogViewModel : Screen {     public HumanApprovalDialogViewModel()     {         Title = "执行审批";     }      private string _title = string.Empty;     public string Title     {         get => _title;         set => SetAndNotify(ref _title, value);     }      private string _message = string.Empty;     public string Message     {         get => _message;         set => SetAndNotify(ref _message, value);     }      // Approve the action     public void Approve()     {         RequestClose(true);     }      // Reject the action     public void Reject()     {         RequestClose(false);     } } 

使用方式与ShowWindow也很相似:

var dialogVm = new HumanApprovalDialogViewModel {     Title = "函数调用审批",     Message = $"是否同意这个操作?" };  bool? result = _windowManager.ShowDialog(dialogVm); 

最大的区别就是模态与非模态。

模态:
当一个模态窗口(如对话框)出现时,它会独占用户的操作焦点。在用户完成该窗口的任务(例如点击“确定”或“取消”)并关闭它之前,无法与应用程序的其他任何窗口进行交互。程序流程也会在此处暂停,等待窗口关闭后返回结果。这就像一个强制性的“选择题”,你必须回答才能继续。常见场景包括文件保存、确认删除等需要用户明确决策的流程。

非模态:
非模态窗口则像一个开放的助手。它显示后,用户可以随时在它和应用程序的其他窗口之间自由切换,无需关闭它。程序也会继续执行,不会被窗口的开启或关闭打断。这就像一个可以随时查阅的“便签”或“计算器”。它常用于工具箱、属性面板或辅助信息窗口,让用户在主任务进行时能方便地获取额外功能或信息。

简言之就是模态就是会阻塞程序运行,要你明确给一个反馈,非模态不会阻塞程序的运行,就单纯显示一个窗体。

效果:

WPF/C#:使用Stylet中的IWindowManager用于显示等待窗体、对话框与消息框

WPF/C#:使用Stylet中的IWindowManager用于显示等待窗体、对话框与消息框

同意就返回true,拒绝或者关闭窗体就返回false。

显示信息框

我们可以发现IWindowManager除了有ShowWindow与ShowDialog方法外还有一个ShowMessage方法,现在来看下这个方法的使用吧!!

1、基本用法 - 只显示消息

_windowManager.ShowMessageBox("你好"); 

效果:

WPF/C#:使用Stylet中的IWindowManager用于显示等待窗体、对话框与消息框

2、带标题的消息框

_windowManager.ShowMessageBox("操作完成", "提示"); 

效果:

WPF/C#:使用Stylet中的IWindowManager用于显示等待窗体、对话框与消息框

3、带确认和取消按钮的消息框

 var result1 = _windowManager.ShowMessageBox("确定要删除这个文件吗?", "确认删除",      MessageBoxButton.OKCancel, MessageBoxImage.Question); 

效果:

WPF/C#:使用Stylet中的IWindowManager用于显示等待窗体、对话框与消息框

4、带是/否/取消按钮和警告图标的消息框

var result2 = _windowManager.ShowMessageBox("文件已修改,是否保存?", "保存确认",     MessageBoxButton.YesNoCancel, MessageBoxImage.Warning); 

效果:

WPF/C#:使用Stylet中的IWindowManager用于显示等待窗体、对话框与消息框

5、带自定义按钮标签的消息框 (使用YesNoCancel按钮以展示更多选项)

var customButtons = new Dictionary<MessageBoxResult, string> {     { MessageBoxResult.Yes, "继续" },     { MessageBoxResult.No, "停止" },     { MessageBoxResult.Cancel, "取消" } }; var result3 = _windowManager.ShowMessageBox("检测到潜在风险,是否继续操作?", "安全警告",     MessageBoxButton.YesNoCancel, MessageBoxImage.Exclamation, MessageBoxResult.No, MessageBoxResult.Cancel, customButtons); 

效果:

WPF/C#:使用Stylet中的IWindowManager用于显示等待窗体、对话框与消息框

6、带文本对齐和流方向的消息框

_windowManager.ShowMessageBox("这是一个从右到左显示的消息框文本", "RTL示例",     MessageBoxButton.OK, MessageBoxImage.Information, MessageBoxResult.None, MessageBoxResult.None,     null, FlowDirection.RightToLeft, TextAlignment.Center); 

效果:

WPF/C#:使用Stylet中的IWindowManager用于显示等待窗体、对话框与消息框

7、完整参数示例

 var fullResult = _windowManager.ShowMessageBox(      "这是一个完整的消息框示例,包含了所有参数的使用",      "完整示例",      MessageBoxButton.OKCancel,      MessageBoxImage.Information,      MessageBoxResult.OK,      MessageBoxResult.Cancel,      null,      FlowDirection.LeftToRight,      TextAlignment.Left); 

效果:

WPF/C#:使用Stylet中的IWindowManager用于显示等待窗体、对话框与消息框

最后

本文梳理了Stylet中IWindowManager的用法,分别是ShowWindow、ShowDialog与ShowMessageBox希望对你有所帮助。

发表评论

评论已关闭。

相关文章