命令绑定到 ViewModel,并在 View 中使用确认逻辑

2024-04-28

寻找最优雅的解决方案将按钮命令绑定到 ViewModel ICommand 属性,同时允许在视图中进行确认。

我想做的事:

  1. 仅允许用户在应该时单击按钮
  2. 单击按钮时,要求确认
  3. 如果确认,则在 ViewModel 中进行工作,否则取消
  4. 不要破坏MVVM架构

可以通过显示 ViewModel 中的消息框来满足确认要求。但是,我不认为这是正确的方法。这不会破坏MVVM吗?如果 CanExecute 依赖于 UI(代码隐藏)和 ViewModel 的状态怎么办?另外,当从 ViewModel 弹出消息框时,可测试性怎么样?

我尝试的另一件事是将 OnClick (到 View)和 Command (到 ViewModel)绑定。虽然Event总是在Command之前执行,但是似乎没有办法取消命令的执行。此外,执行顺序似乎是一个未记录的功能,因此您不应该依赖它。除此之外,它仍然不允许 CanExecute 考虑视图逻辑。

接下来我想出了以下解决方案:

视图 (XAML)

<Window x:Class="WpfApplication1.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    DataContext="{Binding RelativeSource={RelativeSource Self}}">
    <Grid>
        <Button Content="Do Work" Command="{Binding Path=ViewModel.SaveCommand}"/>
    </Grid>
    <SelectTemplateUserControl Visibility="Collapsed" OnTemplateSelected="SelectTemplate_OnTemplateSelected"/>
</Window>

视图(代码隐藏)

public partial class MainWindow : Window
{
    private readonly MainViewModel _viewModel = new MainViewModel();

    public MainWindow()
    {
        InitializeComponent();
    }

    public MainViewModel ViewModel { get { return this._viewModel; } }    

    public ICommand SaveCommand { get { return new RelayCommand<int>(this.Save,                                 this.CanSave);} }

    private bool CanSave(int templateId)
    {
        return this._viewModel.SaveCommand.CanExecute(null);
    }

    private void Save(int templateId)
    {
        var messageBoxResult = MessageBox.Show("Do you want to overwrite?",               "Overwrite?", MessageBoxButton.OKCancel);

        if (messageBoxResult == MessageBoxResult.Cancel)
            return;

        // Call method to hide main Grid and set SelectTemplateUserControl to visible..
    }

    private void SelectTemplate_OnTemplateSelected(object sender, int templateId)
    {
        this._viewModel.SaveCommand.Execute(templateId);
    }
}

视图模型

public class MainViewModel : ViewModelBase
{
    public ICommand SaveCommand { get { return new RelayCommand<int>(this.Save,              this.CanSave); } }

    private bool CanSave(int templateId)
    {
        // Can Save Logic, returning a bool
    }

    private void Save(int templateId)
    {
        // Save Logic....
    }
}

我认为它很好地遵循了 MVVM 模式,并且还实现了单一职责。但这是最好的方法吗?还有其他的可能性吗?


可以通过显示 ViewModel 中的消息框来满足确认要求。但是,我不认为这是正确的方法。这不会破坏MVVM吗?

在使用“MessageBox”等与视图相关的依赖项时保留 MVVM 样式的一种方法是将它们封装并注入到视图模型中。因此,您可以通过请求一个来表达依赖性IDialogService在构造函数中:

public class MainViewModel : ViewModelBase
{
    private readonly IDialogService _dialog;

    public MainViewModel(IDialogService dialog)
    {
        _dialog = dialog;
    }
}

然后你从视图中传递实现:

private readonly MainViewModel _viewModel = new MainViewModel(new DialogService());

该界面封装了您需要的任何功能,例如“警报”、“确认”等。

public interface IDialogService
{
    bool Confirm(string message, string caption = "Confirm");
}

并使用它来实现它MessageBox,或任何其他方法(并切换单元测试的虚拟实现):

public class DialogService : IDialogService
{
    public bool Confirm(string message, string caption)
    {
        return MessageBox.Show(message, caption, MessageBoxButton.OKCancel) == MessageBoxResult.OK;
    }
}

这样您就可以将所有确认逻辑从视图移动到视图模型,其中“保存”方法将如下所示:

private void Save()
{
    if (!_dialog.Confirm("Do you want to overwrite?", "Overwrite?"))
        return;

    this.SaveCommand.Execute(null);
}

如果 CanExecute 依赖于 UI(代码隐藏)和 ViewModel 的状态怎么办?

如果您担心测试,那么没有什么CanExecute取决于应该在代码隐藏中——您应该将类​​似的内容移动到视图模型中。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

命令绑定到 ViewModel,并在 View 中使用确认逻辑 的相关文章

随机推荐

  • 将数组中的项目移动到最后一个位置

    我有一系列对象 我想将选定的对象移动到数组中的最后一个位置 我如何在 javascript 或 jquery 中执行此操作 这是我的一些代码 var sortedProductRow this product row for var s i
  • 连接到 Wikipedia API 的 WebRequest

    这可能是一个可悲的简单问题 但我似乎无法格式化帖子网络请求 响应以从维基百科API http en wikipedia org wiki Wikipedia API 如果有人可以帮助我查看我的问题 我已在下面发布了我的代码 string p
  • Spring MVC - 两次提供内容

    我已经花了一周时间寻找有关如何将内容服务器到我的网页的指导 两次 因为使用 Model 或 ModelAndView 切断内容一次可以工作 但如果用户再次与页面交互 我希望它加载更多内容同一页 Java Spring 后端方法 Get 有效
  • 调用需要很长时间执行的.php时如何解决“mod_fastcgi.c.2566意外的文件结束(可能是fastcgi进程死亡)”?

    在我的 php 应用程序中 我恢复 db2 数据库 它工作正常 但这里有一个巨大的 2 9GB 最后是500 Internal Server Error 我使用 exec 从 php cp db2 等运行 unix shell 命令 从 f
  • 带有 Google iframe 链接的 Google 静态地图图像

    我正在尝试显示一个谷歌静态地图 单击该地图时 将打开一个更大的 iframe 用户可以在其中平移 缩放等 JSF 在这里 http jsfiddle net thong Q4FE7 代码如下 div a class various fanc
  • Apache NiFi ExecuteScript:通过映射文件替换 Json 值的 Groovy 脚本

    我正在 Groovy 脚本上使用 Apache NiFi 0 5 1 以将传入的 Json 值替换为映射文件中包含的值 映射文件如下所示 它是一个简单的 txt Header1 Header2 Header3 A some text A2
  • 如果我使用不同数量的核心,XGBoost 会产生相同的结果吗?

    我在两台机器上安装了完全相同版本的 XGBoost 0 4 两台机器之间的唯一区别是 RAM 和内核数量 8 与 16 使用完全相同的数据 我无法重现相同的结果 它们略有不同 小数点后第四 第五位 种子保留为默认值 它是高度特定于实现的 但
  • Android:如何禁止应用程序在扫描 NFC 标签时重新打开?

    我正在编写一个 Android 应用程序 用于从 Mifare Classic 卡 4k 读取数据 我已经编辑了 AndroidManifest xml 文件 以便应用程序启动 或者我可以选择另一个使用 NFC 的应用程序 但是 当我的应用
  • 在 yii2 中搜索两个日期

    日期可以用不同的格式表示 表格本身看起来像这样 book varchar 250 NOT NULL date INT NOT NULL 现在我的问题是我无法在两个日期之间的范围内实现搜索 例如 有 5 本书 日期不同 但开始日期开始 在31
  • Spring-WS WSDL生成问题

    我正在尝试制作一个非常简单的 Web 服务 但在让 spring 生成正确的 wsdl 时遇到一些困难 我已尽力复制此示例春季教程 http static springsource org spring ws sites 2 0 refer
  • 在 AngularJS 中使用 iFrame

    Using Angular 1 2 我正在尝试找出一种 有角度 的方式来加载 iFrame 但我在任何地方都找不到任何教程 任何真正的讨论 基本上 我有一个显示链接列表的搜索页面 单击链接应调用控制器中的一个函数 该函数将数据 可能通过 h
  • 测试在私有变量中保留其状态的类

    我正在为我的班级编写单元测试 此类在某些情况下保留其状态private变量 我不想公开暴露 所以场景是 如果我调用一个方法 第一次它会保持该状态private属性并调用委托方法并返回一些结果 当我第二次调用相同的方法时 输出将根据之前的输入
  • 如何在 Perl 中将纪元时间转换为正常时间?

    我正在尝试编写一个 Perl 脚本来解析日志 其中每行的第二个值是日期 该脚本接受三个参数 输入日志文件 开始时间和结束时间 开始时间和结束时间用于解析出每行上位于这两个时间之间的特定值 但为了正确运行这个 我将开始和结束时间转换为纪元时间
  • BigQuery 表中可以按小时进行分区吗?

    谷歌文档只讨论日常分区 但是模型中是否有任何东西阻碍人们将分区填充到具有其他时间段 例如 小时或周 的表中 在 小 表中进行分区是否有任何限制或缺点 现在only DAY支持分区表 不支持按小时或按月 有几个对新功能的功能请求 但没有实施时
  • 在 Spring 中以编程方式解析 AliasFor 注释值

    我有一个注释 Target ElementType TYPE Retention RetentionPolicy RUNTIME public interface A Class value 这是在课堂上使用的 B D class publ
  • 如何通过 Xcode 4 的组织者提交应用程序?我收到错误

    我安装了 Xcode 4 认为它与 Xcode 3 类似 但现在我无法使用组织器将我的二进制文件发送到 App Store 我认为这是执行此操作的正确方法 有人让它正常工作吗 不确定我需要更新什么设置 我得到的只是一条 无效的二进制 消息
  • WebSocket 和负载平衡是瓶颈吗?

    当有一堆充当 WebSocket 无人机的系统和这些无人机前面的负载均衡器时 当 WebSocket 请求进入 LB 时 它会选择一个 WebSocket 无人机 并建立 WebSocket 我在 ELB 上使用 AWS ELB tcp S
  • 自动创建 Visual C++ 故障转储

    有没有办法在应用程序崩溃时 在 Windows 操作系统上 自动创建故障转储文件 就像我可以使用附加的 Visual Studio 调试器进行保存一样 也就是说 我希望能够使用自动创建的故障转储文件在 Visual Studio 中调试我的
  • 什么是排列索引?

    我正在阅读 加速 C 我不明白练习 5 1 设计并实现一个程序 根据以下输入生成排列索引 排列索引是其中每个短语由短语中的每个单词索引的索引 The quick brown fox jumped over the fence The qui
  • 命令绑定到 ViewModel,并在 View 中使用确认逻辑

    寻找最优雅的解决方案将按钮命令绑定到 ViewModel ICommand 属性 同时允许在视图中进行确认 我想做的事 仅允许用户在应该时单击按钮 单击按钮时 要求确认 如果确认 则在 ViewModel 中进行工作 否则取消 不要破坏MV