显示模式对话框并获取结果

2024-01-05

我有一个静电WindowService帮助我创建新窗口和模式对话框的类。 到目前为止,我所拥有的是这样的:

/// <summary>
/// Opens a new window of type <paramref name="newWindowType"/> and closes the <paramref name="oldWindow"/>
/// </summary>
/// <param name="oldWindow">The window which should be closed (Usually the current open window)</param>
/// <param name="newWindowType">The type of the new window to open</param>
public static void ShowNewWindow(Window oldWindow, Type newWindowType)
{
    ((Window)Activator.CreateInstance(newWindowType)).Show();
    oldWindow.Close();
}

我的视图模型引发了一个事件,并且视图订阅了该事件。在视图的事件处理程序中,它调用WindowService.ShowNewWindow(this,The type here)。这很好用。
我的模式对话框创建方法也将以类似的方式工作。唯一的区别是信息将返回到视图(在事件处理程序中),因此视图必须在代码中显式将该信息传递到视图模型。这违反了 mvvm 模式,我不知道如何让视图模型等待视图在事件引发后返回值。
有更好的方法吗?


啊,这个老栗子。

many关于如何实现这一目标有不同的变体,但是这是我的两分钱。

这里的主要想法是确保您的View and View Model彼此不了解,因此你们的View不应订阅您的事件View Model, 和你的View Model不应直接调用您的服务并提供视图Type.


不要使用事件,而使用命令

我的建议是使用ICommand实现而不是依赖于静态服务类,因为您的类将始终依赖于该服务,并且一旦您发送视图Type到此服务,那么 MVVM 模式就会丢失。

因此,首先,我们需要某种命令来打开给定的窗口Type,这是我想出的:

public class OpenWindowCommand : ICommand
{
    public bool CanExecute(object parameter)
    {
        TypeInfo p = (TypeInfo)parameter;

        return p.BaseType == typeof(Window);
    }

    public event EventHandler CanExecuteChanged
    {
        add { CommandManager.RequerySuggested += value; }
        remove { CommandManager.RequerySuggested -= value; }
    }

    public void Execute(object parameter)
    {
        if (parameter == null)
            throw new ArgumentNullException("TargetWindowType");

        //Get the type.
        TypeInfo p = (TypeInfo)parameter;
        Type t = p.BaseType;

        if (p.BaseType != typeof(Window))
            throw new InvalidOperationException("parameter is not a Window type");

        //Create the window.
        Window wnd = Activator.CreateInstance(t) as Window;

        OpenWindow(wnd);
    }

    protected virtual void OpenWindow(Window wnd)
    {
        wnd.Show();
    }
}

该类继承自ICommand并指定接受的实现Type,它代表期望的View我们想要打开的。请注意,我已将方法标记为virtual,我稍后会解释这部分。

下面是我们如何在我们的程序中使用这个命令View Model:

public class MainWindowViewModel
{
    public OpenWindowCommand OpenWindowCommand { get; private set; }

    public MainWindowViewModel()
    {
        OpenWindowCommand = new OpenWindowCommand();
    }

    ...
}

现在我们已经创建了命令,我们只需要绑定一个Button to it:

<Button Content="Open Window"
        Command="{Binding OpenWindowCommand}"
        CommandParameter="{x:Type local:MyWindow}"/>

这里要注意的一件事是我正在使用x:Type as the CommandParameter,这是Window执行此命令时将创建该文件。


但是对话框呢?

我们上面所取得的成果只是half根据要求,我们现在需要一些能够显示dialog并将结果输出到我们的View Model,这并不那么棘手,因为我们现有的大部分内容已经有了OpenWindowCommand.

首先,我们需要创建命令:

public class ShowDialogCommand : OpenWindowCommand
{
    private Action _PreOpenDialogAction;
    private Action<bool?> _PostOpenDialogAction;

    public ShowDialogCommand(Action<bool?> postDialogAction)
    {
        if (postDialogAction == null)
            throw new ArgumentNullException("postDialogAction");

        _PostOpenDialogAction = postDialogAction;
    }

    public ShowDialogCommand(Action<bool?> postDialogAction, Action preDialogAction)
        : this(postDialogAction)
    {
        if (preDialogAction == null)
            throw new ArgumentNullException("preDialogAction");

        _PreOpenDialogAction = preDialogAction;
    }

    protected override void OpenWindow(System.Windows.Window wnd)
    {
        //If there is a pre dialog action then invoke that.
        if (_PreOpenDialogAction != null)
            _PreOpenDialogAction();

        //Show the dialog
        bool? result = wnd.ShowDialog();

        //Invoke the post open dialog action.
        _PostOpenDialogAction(result);
    }
}

我们正在利用我们的OpenWindowCommand通过继承它并使用它的实现,而不必将其全部复制到我们的新类中。该命令需要一个Action这是对你的方法的引用View Model,您可以选择定义一个动作before or after(或两者)显示一个对话框。

下一步是改变我们的View Model所以它创建了这个新命令:

public class MainWindowViewModel
{
    public OpenWindowCommand OpenWindowCommand { get; private set; }
    public ShowDialogCommand ShowDialogCommand { get; private set; }

    public MainWindowViewModel()
    {
        OpenWindowCommand = new OpenWindowCommand();
        ShowDialogCommand = new ShowDialogCommand(PostOpenDialog);
    }

    public void PreOpenDialog()
    {
        throw new NotImplementedException();
    }

    public void PostOpenDialog(bool? dialogResult)
    {
        throw new NotImplementedException();
    }
}

该命令的用法实际上与以前相同,但它只是引用了不同的命令:

<Button Content="Open Window"
        Command="{Binding ShowDialogCommand}"
        CommandParameter="{x:Type local:MyWindow}"/>

就这样,一切都是松散耦合的,这里唯一真正的依赖关系是你的View Model取决于你的ICommand类。


最后几句话

The ICommand我创建的类充当控制器之间的控制器ViewView Model确保它们彼此不了解,并强制执行 MVVM 模式。

就像我在这个答案开始时所说的那样,有很多方法可以实现这一点,但是我希望您现在更加开明一点。

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

显示模式对话框并获取结果 的相关文章

  • 为什么序列操作算法谓词通过复制传递?

    我想知道为什么函子通过副本传递到algorithm http en cppreference com w cpp algorithm功能 template
  • C++编程风格

    我是一名老 但不是太老 Java 程序员 决定学习 C 但我见过很多 C 编程风格 嗯 实在是太丑了 将类定义放在头文件中 并将方法放在不同的源文件中的所有内容 突然调用函数 而不是使用方法课堂内 这一切似乎 都是错误的 那么最后 我还有什
  • 如何等到我的批处理文件完成

    我正在做一个程序 我需要启动 cmd 并启动一个批处理文件 问题是我正在使用MyProcess WaithForexit 我认为它不会等到批处理文件处理完成 它只是等待 cmd 关闭 到目前为止我的代码 System Diagnostics
  • 工具提示气球在 5 秒后消失

    我将属性 AutoPopDelay 设置为 60000 但每次我将鼠标悬停在关联元素上时 即使鼠标指针在元素上保持静止 气球也只会保持打开状态 5 秒 关于可能导致这种情况的原因有什么想法吗 编辑 我正在使用 WinForms 稍微使用一下
  • 如何检查字节数组是否为空?

    我正在下载word文件GetSourceAttachment方法 当此方法返回空字节时 我的字节Attachment数组给出错误 对象引用未设置对象实例 当我检查长度时它给出错误Attachment in if健康 状况 任何人都可以帮我默
  • 哪种 C# 模型将序列化为具有动态属性名称的 JSON 对象,每个属性名称都有一个值列表列表?

    当我使用 Newtonsoft Json 序列化时 C 中的什么数据结构 集合会给我这样的结果 其中属性名称 data point1 是动态的并在运行时定义吗 data data point1 string string string st
  • 如何获取变量的各个字节的值?

    我知道要获取变量类型使用的字节数 您可以使用sizeof int 例如 当您存储具有该变量类型的数字时 如何获取所使用的各个字节的值 IE int x 125 您必须知道每个 字节 中的位数 通常为 8 然后 您可以通过将 int 与适当的
  • 多维向量

    如何创建 2D 矢量 我知道在二维数组中 我可以这样表达 a 0 1 98 a 0 2 95 a 0 3 99 a 0 4 910 a 1 0 98 a 1 1 989 a 1 2 981 a 1 3 987 如何使用 C STL Vect
  • 编程实践:将 ExecuteNonQuery 与 SqlDataAdapter 结合使用

    public DataTable UserUpdateTempSettings int install id int install map id string Setting value string LogFile SqlConnect
  • sizeof可以返回0(零)

    在 C 或 C 中 sizeof 运算符是否有可能返回 0 零 如果可能的话 从标准的角度来看是否正确 在 C 中 空类或结构有一个sizeof根据定义至少为 1 根据 C 标准 9 3 类 类类型的完整对象和成员子对象应具有非零大小 在
  • 使用 iText7 + C# 读取 pdf 中的文本,无法识别文本

    我想从pdf文档中读取数据 我使用 iText7 var src
  • struct tm->tm_yday 是否给出了正确的闰年值?

    假设我想获取自 1 月 1 日以来经过的天数 这会返回闰年的正确值吗 struct tm now tm struct timeval tv time t currtime gettimeofday tv NULL currtime tv t
  • 如何在 XAML Metro 应用程序中禁用网格(面板)?

    我想在 XAML Metro 应用程序中模拟模式对话框 因此 我打算在所有控件上设置 IsEnabled false 除了作为模式对话框的控件之外 显然 IsEnabled 不在 Grid 中 不在 Panel 中 不在 Framework
  • C#:在这种情况下我将如何过滤掉不需要的命名空间?

    这更像是一个与语言无关的问题 而不是特定于 C 的问题 但由于它涉及命名空间 我认为我应该将其标记为与 NET 相关 假设您有一堆代表名称空间的字符串 System System Windows System Windows Input S
  • C# 中退出控制台应用程序的命令是什么?

    C 中用于退出控制台应用程序的命令是什么 您可以使用Environment Exit 0 and Application Exit Environment Exit 0 更干净 https web archive org web 20201
  • 在ubuntu中安装pyinterval

    我正在尝试安装 python 库 pyinterval 它需要 crlibm C 标头 我已安装该标头 没有错误 但似乎是问题的根源 当我跑步时 sudo easy install pyinterval 我得到以下信息 Searching
  • 从进程中获取当前打开的Word文档

    目标是获取在我有流程参考的 Microsoft Word 实例中打开的文档的完整路径 伪代码示例 Process myWordProcess something This is my process reference DocumentIn
  • 为什么 C++ 中的“按 Enter 继续”代码不起作用?

    所以 我正在用 C 为孩子们制作一个简单的测验程序 我真的是一个编程初学者 我想要做的是要求用户在第一个问题后按 Enter 键 并且只有按 Enter 键后 第二个问题才可见 但由于某些原因 C 不会等待用户在 cin 语句中输入输出 而
  • 在 C# 中生成 Excel 列字母的最快函数

    接受 int 并返回包含一个或多个字母的字符串以便在 Excel 函数中使用的最快 C 函数是什么 例如 1 返回 A 26 返回 Z 27 返回 AA 等 这被调用了数万次 并且占用了生成包含许多公式的大型电子表格所需时间的 25 pub
  • 从内存加载程序集

    我正在移植一个 Java 应用程序 其中类在运行时从内存 字节数组 加载并 执行 我试图在 C 中实现同样的目标 但遇到问题 System IO FileNotFoundException异常 当尝试从字节数组加载程序集时 使用AppDom

随机推荐

  • 无法使用 Avro 和嵌套类注册模式

    每当 Avro 类模式中有嵌套对象时 就不会保存 总是会遇到异常 比如 org apache kafka connect errors ConnectException Tolerance exceeded in error handler
  • main函数参数的argv字符串位于哪里?

    在C C 中 main函数接收的参数类型为char int main int argc char argv return 0 argv是一个数组char 并指向字符串 这些字符串位于哪里 它们是在堆 栈还是其他地方 这是 C 标准 n125
  • -fno-unwind-tables 和 -fno-asynchronous-unwind-tables 不起作用 NDK clang++

    我正在使用 ndk21 附带的 clang 编译我的 C 代码 我已设置编译器标志 fno unwind tables 和 fno asynchronous unwind tables 但展开表中的条目数不会减少 我还通过设置相反的 fun
  • 整理 PHP 和 HTML 代码?

    我想知道是否有人可以帮助我 我一直在使用 HTML tidy 和 eclipses 内置函数来整理我的代码 我在以下情况中遇到了很大的麻烦 当 HTML 通过包含在文件之间分割时 使用正确的缩进构建结果有助于通过浏览器工具进行调试 PHP
  • Python 中的 zipfile 生成的 ZIP 文件不太正常

    在我的项目中 创建了一组文件并将其打包为 ZIP 存档 以便在 Android 手机上使用 Android 应用程序打开此类 ZIP 文件来读取初始数据 然后将其工作结果存储到相同的 ZIP 中 我无法访问上述 Android 应用程序的源
  • C# OpenXML (Word) 表自动适应窗口

    打开一个包含表格的 Word 2007 2010 文档 选择该表格并右键单击 选择 自动调整 gt 自动调整到窗口 如何使用 OpenXML SDK 2 5 在 C 中实现此操作 您可以将表格的宽度设置为页面的 100 或 5000 个百分
  • 何时使用 Malloc 而不是 New [重复]

    这个问题在这里已经有答案了 重复 在什么情况下使用 malloc 和 new https stackoverflow com questions 184537 in what cases do i use malloc vs new 只是重
  • ML.net - 列标签中第 1 行的错误值

    我正在关注虹膜教程 https www microsoft com net learn apps machine learning and ai ml dotnet get started windows对于 ML Net 我输入了说明而不
  • 未解决的参考 BuildConfig

    当我尝试重建我的项目时 出现以下错误 warning flag is not supported by this version of the compiler Xallow no source files warning flag is
  • 基于Boost foreach实现enumerate_foreach

    作为这个问题的序言 我一直在一个更大的工具包中实现各种 C 实用函数和 当我必须这样做时 宏供我自己使用 最近我一直在制作各种基于 BOOST FOREACH 的循环宏以及可迭代的意识函数 长话短说 我在制作时遇到了困难枚举循环它使用 BO
  • Symfony 1.4 会话随机丢失

    这是我几个月前开始尝试的一个问题 从那以后我一直试图解决但没有成功 Symptoms symfony 在随机的时间间隔内丢失会话信息并注销用户 它似乎与网站的负载有某种联系 当负载较高时 用户注销似乎会更频繁 甚至可能会快至 30 秒 环境
  • 如何将 META 重新映射到 ALT?

    我在 Ubuntu 中使用 emacs 如何将 META 重新映射到 ALT 键 如果您在 gnome 终端中运行 emacs 则 gnome 终端可能会捕获您的 alt 键以打开 gui 菜单 文件 编辑等 您可以通过选择 编辑 gt g
  • Docker:服务器的空响应

    我在连接 docker 容器时遇到问题 服务器返回空响应 但配置似乎是正确的 当我使用 docker compose up 命令时 一切看起来都很好并且工作正常 但是我从服务器得到空响应 我仔细检查了端口映射 但我没有注意到任何东西 这是撰
  • git 不显示 unicode 文件名

    我在 Mac OS X 上使用 git 2 5 4 我的文件名包含 git 正在用转义符显示它 有没有办法让它使用unicode并显示字符 终端显然可以处理它 gt ls S l gt git status Untracked files
  • Discord.py重写获取公会成员列表

    只是想知道我将如何获取公会中所有当前成员的列表 然后将其作为消息返回 如果你想获取特定公会的成员数量 可以使用len guild members 如果您想获取列表 只需使用guild members 如果你想发送它 它可能不起作用 因为 D
  • Subversion - 是否可以禁用所有提交并使存储库只读?

    我有一个颠覆存储库 它是另一个远程存储库的镜像 我每周都会使用 svnsync 来镜像存储库 镜像存储库 本地副本 仅用于备份 我希望将镜像存储库保持为只读 即任何人都不能对此存储库提交任何更改 但他们可以使用它来读取源文件 因为它比远程存
  • 如何使用 mono 编译目录中的所有文件?

    我想用 mono 编译一个由多个文件组成的 C 应用程序 全部在 1 个目录中 我需要什么命令 Use gmcs out yourapp exe pkg dotnet cs or gmcs out yourapp exe pkg dotne
  • 从双精度数中删除 .0

    我正在尝试动态显示字符串中的数字 因此如果数字有小数 则显示它们 但如果没有 则不显示 0 示例 将 5 5 显示为 5 5 将 5 0 显示为 5 这是我到目前为止所拥有的 答案是双 double temp answer long tem
  • 如何在Python中进行指数和对数曲线拟合?我发现只有多项式拟合

    我有一组数据 我想比较哪一行最能描述它 不同阶的多项式 指数或对数 我使用 Python 和 Numpy 对于多项式拟合 有一个函数polyfit 但我没有发现这样的指数和对数拟合函数 有吗 或者另外如何解决 用于装配y A B log x
  • 显示模式对话框并获取结果

    我有一个静电WindowService帮助我创建新窗口和模式对话框的类 到目前为止 我所拥有的是这样的