WPF 的 ICommand 如何表示为与 UI 松散耦合的简单字符串?

发布于 2024-10-31 10:11:12 字数 1960 浏览 2 评论 0原文

过去,在 Windows 窗体中,我都使用了 复合 UI 应用程序块 的部分内容与一些集中式命令处理和安全规则相结合,以实现松散耦合的 MVC 方法来连接命令执行绑定的接口。我想知道如何在 WPF 中使用 ICommand 或 RoutedCommand 执行此操作?

我之前的实现将包含以下内容:

  1. 将每个命令与基于 REST 的 URI 形式的字符串相关联,例如 cmd://myapp/orders/create
  2. 编写自定义 ICommand (不是与 WPF 混淆),它将处理命令执行,它只有一个 Execute() 方法和 CanExecute 属性以及 Undo() 和`CanUndo(如果支持撤消功能)。
  3. 执行命令所需的接口对象将被松散地绑定
    1. 处理 Click 事件,该事件不知道要执行哪个命令,而只是向集中式 CommandManager 传递要执行的命令名称。
    2. 一旦CommandManager收到命令执行,它将简单地使用复合 UI 应用程序块来引发命令事件。
    3. 在实际执行命令之前,命令管理器会执行安全检查,这基本上是询问我的 SecurityManager 登录用户是否可以执行命令字符串,安全规则通过 XML 文件加载,并包含以下内容模式,例如“cmd://myapp/finance/*”
    4. 一旦在接收命令上引发命令事件,它将负责通过基于视图模型的依赖关系确定状态和上下文。

我喜欢这种方法,因为它易于编写、松散耦合,并且命令只允许通过通过 DI 找到的视图模型获取接口状态。 复合 UI 应用程序块 还让我可以轻松地“启用/禁用/unavailable"

我可以类似地复制除了命令的“字符串”表示之外的几乎所有内容,这一点至关重要,因为我们编写的安全上下文可以通过处理诸如 cmd://myapp/ 之类的命令模式来锁定整个部分Finance/*,然后我们还可以让用户决定他们的命令快捷方式绑定等。

对我来说,关键要求是:

  1. 命令需要表示为字符串,这是绝对要求。
  2. 必须能够声明命令字符串是“启用”、“禁用”和“不可用”(这意味着它应该隐藏在 UI 中。
  3. 界面元素必须不知道如何处理命令,或者如何提供上下文,这是命令责任本身通过它发现的视图模型对象
  4. 处理引发事件以执行命令执行以及维护撤消堆栈。

必须集中,即我需要一个命令管理器对象来 :我刚刚考虑过如何使用 MEF 导出来公开提供命令名称的自定义元数据来提供命令绑定,然后 ImportMany 可以将它们加载到我的 CommandManager 中,现在这只是一个问题

  1. 告诉接口项它们调用的命令字符串,并且
  2. 允许命令字符串更改状态(启用/禁用/不可用)

:我已经考虑过一个解决方案。我的 CommandManager 接受 Register(Control, String) 方法,可以使用命令字符串注册控件,然后命令管理器可以处理启用/禁用/隐藏UI 元素的状态发生变化并将事件绑定到它们,这提供了更大的灵活性和解耦,同时还允许用户自定义(移动菜单、按钮配置、键盘快捷键等)。这引起了一个担忧,尽管我没有使用 WPF 提供的 ICommand 设施的单点,最终我认为这并不重要,但我想知道命令设施是否WPF 提供的功能可以按照我定义的简单方式使用。另一个优点是此方法不是 WPF 特定的,可以在任何地方使用。

In the past with windows forms I both used parts of Composite UI Application Block combined with some centralised command handling and security rules to achieve a loosly coupled MVC approach to interface to command execution binding. I would like to know how to do this in WPF with the ICommand or RoutedCommand?

My prior implementations would consist of the following:

  1. Associate every command with a string in the form of a REST based URI, such as cmd://myapp/orders/create
  2. Write a custom ICommand (not to be confused with WPF) which would handle the command execution, it just had an Execute() method, and CanExecute property along with Undo() and `CanUndo if it supported undo capabilities.
  3. Interface objects required to execute the command would then be bound loosely by
    1. Handling the Click event which would not know about which command to execute, but merely pass the centralised CommandManager a command name to be executed.
    2. Once the CommandManager recieves a command execution it would simply use the many-to-many capabilities in Composite UI Application Block to raise the command event.
    3. Before the actual command execution the command manager performs a security check which is basically assking my SecurityManager if the logged in user can perform a command string, security rules are loaded through an XML file and consist of patterns, such as 'cmd://myapp/finance/*'
    4. Once the command event is raised on the recieving command it would then be responsible for determining state and context through view-model based dependencies.

I like this approach because it's easy to write, loosly coupled, and commands are only allowed to obtain interface state through view-model's which are found via DI. Composite UI Application Block also made it easy for me to "enable/disable/unavailable"

I can similarly replicate almost everything exccept the 'string' representation of a command, this is vital as the security context we have written can lock down a whole section by handling command patterns such as cmd://myapp/finance/*, we can also then let the user decide their command shortcut bindings etc.

Key requirements for me are:

  1. Commands need to be represented as strings, this is an absolute requirement.
  2. Must be able to state a command string is "enabled", "disabled", and "Unavailable" (meaning it should be hidden in the UI.
  3. Interface elements must not know how to handle a command, or how to provide context, this is the commands responsibility itself via view-model objects it discovers.
  4. Command execution must be centralised, i.e. I need a command manager object that handles raising the event to perform the command execution along with maintianing an undo stack.

EDIT: I've just thought about how to provide the command binding by using MEF exports to expose custom metadata providing the command name, an ImportMany can then load these up in my CommandManager, now it's just a matter of

  1. Telling interface items a Command String that they invoke, and;
  2. Allowing command strings to have state changed (enabled/disabled/unavailable).

EDIT 2: I have thought about a solution where my CommandManager accepts a Register(Control, String) bethod where one can register a control with a command string, the command manager can then handle the enabling/disabling/hiding of UI elements as their state changes and bind events to them, this provides much greater flexibility and decoupling as while also alowing for user customizing (moving menus, button configurations, keyboard shortcuts etc..). This raises a concern though that I'm not using a single point of the ICommand facility provided by WPF, in the end I don't think it matters, but I would like to know if the commanding facility provided with WPF could be used in such a simple way as I have defined. The other advantage is this method is not WPF specific and can be used anywhere.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

那一片橙海, 2024-11-07 10:11:12

在我看来,你正在努力适应你曾经在 winforms 中使用的模式,也可以在 wpf 中使用。这通常不是最好的方法。

但具体针对您的问题,我只想说:如果您完全跳过 ICommand,那么您肯定会丢失 wpf 在幕后所做的事情。例如:ICommands CanExecute 方法。 WPF 命令管理器根据用户对应用程序的输入重新查询该方法。否则,您必须自己处理“启用”/“禁用”/“不可用”状态更改的传播,并实现自己的逻辑来启用/禁用按钮。

命令不仅可用于单击事件。

最后:命令可以在没有 WPF 的情况下执行 - 它只是一个接口,没有显式绑定到 wpf

it seems to me you are bending yourself to fit a pattern you once used in winforms to be used in wpf also. that usually is not the best approach.

but specific for your problem I just wanted to say: if you are skipping ICommand entirely you definately loose stuff wpf does behind the scenes. For example: ICommands CanExecute method. The WPFs commandmanager requeries that method depending on user input to your application. You'd otherwise have to handle propagation of "enabled"/"disabled"/"unavailable"-State changes yourself and implement your own logic to enable/disable the button.

also commands can be used for more than just Click events.

and last: commands can be executed without WPF - it's just an interface and not explicitly bound to wpf

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文