【问题标题】:Command binding in multiwindow WPF app多窗口 WPF 应用程序中的命令绑定
【发布时间】:2011-03-25 19:49:41
【问题描述】:

我的应用程序可以有多个设计器窗口。每个窗口由几个用户控件组成,这些控件在 RelayCommands 的帮助下进行动态通信。我创建了以下类作为指挥基础设施的骨干。

public static class Commands
{
    public static readonly RoutedCommand EntityEditRequest = new RoutedCommand();
    public static  RelayCommand EntityEditorChangeRequest;
    public static RelayCommand XMLUpdateRequest;
    public static RelayCommand SaveRequest;   
}

用户控件的每个视图模型都会在构造函数中执行类似的操作

 public XMLEditorViewModel()
 {
        Commands.Commands.SaveRequest = new RelayCommand(Save_Executed);
        Commands.Commands.XMLUpdateRequest = new RelayCommand(UpdateXML); 
 }

但是,我完全忽略了应用程序可以有多个窗口这一点。当每个窗口打开时,都会为该特定窗口设置静态命令。

例子:

窗口 A 已打开 - 用户控件的构造函数设置了 RelayCommands,一切正常。

窗口 B 打开 - 用户控件的构造函数设置了 RelayCommands。窗口 A 的命令绑定丢失!

因此,当我将选项卡更改为窗口 A(窗口为选项卡)时,没有任何命令起作用。

我需要一些想法,这样当我更改选项卡时,活动窗口总是会设置命令。我可以尝试将命令放在 tab_selection_changed 事件中,但不知何故它对我来说看起来很糟糕。有没有合适的方法来做到这一点?非常感谢任何帮助。

编辑:

这个问题在读者中有点令人困惑。我不是想为一个命令创建多个订阅者。在任何给定点,只有一个窗口处于活动状态。这个窗口由几个用户控件组成——其中一些是在命令的帮助下动态加载的;但是每个命令都由单个视图模型类处理-因此没有多个订阅者。我的问题是应用程序可以在选项卡中加载多个窗口——在任何给定点只有一个窗口处于活动状态——但用户可以对不同的选项卡执行操作并使另一个窗口处于活动状态。当视图模型构造函数分配静态 RelayCommands 时,当每个新窗口被加载时,静态命令被设置为一个新的绑定。

窗口一个打开的窗口视图模型构造函数将静态命令绑定到它的对象命令处理程序。窗口 A 处于活动状态。指挥就好了。

窗口 B 加载-窗口 B 视图模型构造函数将静态命令绑定到其对象命令处理程序。窗口 B 处于活动状态。指挥就好了。

现在,用户选择窗口 A 选项卡将窗口 A 设置为活动状态。指挥是行不通的。当然不会,因为 Command 绑定到 Window B 命令处理程序。

理论上,静态命令可以处理这种情况,因为在任何给定点都只有一个活动窗口。但是怎么做??

【问题讨论】:

  • 命令的重点是更好地将逻辑与设计分离,使用事件使命令工作是错误的方法。
  • @Danny-maybe,但这完全不同,我有正当理由这样做。这里的问题是当有很多标签窗口时如何使全局命令绑定到活动窗口。

标签: wpf mvvm command icommand relaycommand


【解决方案1】:

全局命令应该是CompositeCommand 或类似方法(CompositeCommand 来自 Prism)。这将允许多个孩子注册该命令。

  public static CompositeCommand SaveCommand = new CompositeCommand();

然后可以跨 ViewModel 或在适用的情况下访问该命令...

  SaveCommand = new DelegateCommand<object>(Save, CanExecuteSave);
  GlobalCommands.SaveCommand.RegisterCommand(SaveCommand);

然后您可以利用IActiveAware interface 来定义哪个Window 是活动Window 并相应地执行命令。

creating globally available commands 上还有一个 MSDN 帖子。不要忘记取消注册命令以避免内存泄漏。

【讨论】:

  • @Aaron-multiple children binding 不是问题。请阅读我在帖子中的编辑。
  • @Jimmy 这是为了显示应该如何设置全局命令;利用 IActiveAware 接口和复合方法来指挥。您当前的设计本质上是高度耦合的;您正在尝试将命令绑定绑定到活动实例。使用 IActiveAware 策略,因此将根据焦点窗口激活/停用命令。
  • @Aaron-interesting。我需要在星期一试试这个,我会回复你的。
  • 好吧,我查看了 IActiveaAware,我明白你的意思了。在我的情况下这并不容易,因为我不能在应用程序中使用任何框架(如棱镜) - 所以我必须在没有 RegionManager 的情况下这样做。当窗口处于活动状态时,我会找到一些方法来激活 IActiveAware 对象。但是是的——你给了我答案。
【解决方案2】:

你为什么决定把它放到静态类中?

class XMLEditorViewModel
{
    public ICommand SaveRequest { get; private set; }

    public XMLEditorViewModel()
    {
        SaveRequest = new RelayCommand(Save_Executed)?
    }
}

【讨论】:

  • Save 之类的命令通常是静态的,因为您不希望在创建新实例和 Save 定义时弄乱每个 ViewModel。命令的静态方法为应用程序提供了全局方法;这将允许您在相关的地方注册...而不是在您使用 Save 的任何地方创建一个。
  • @snowbear-因为窗口中有许多用户控件,并且该命令可以由任何用户控件触发。并不是该命令会被 XMLEditorView 触发
【解决方案3】:

可以在静态类上定义非特定视图的命令。

视图特定的命令应该在视图模型上定义, 作为 DataContext 传递给查看,启用单独的实现 对于具有不同视图模型的不同视图, 或者至少让视图传递一个 CommandParameter 可用于识别它们(例如对视图的引用)或它们的 DataContext。

如果命令是静态的,只注册一次, 也许在视图模型使用的单例上。

【讨论】:

  • @Danny-请阅读我编辑的帖子。我的问题是如何根据多窗口场景中活动窗口的变化重新绑定静态命令
  • 我的意思是,如果你稍微改变你的设计,你不必重新绑定它们。
【解决方案4】:

创建一个全局可用的命令,创建一个 DelegateCommand 或 CompositeCommand 的实例并通过静态类公开它。

公共静态类 GlobalCommands { 公共静态 CompositeCommand MyCompositeCommand = new CompositeCommand(); } 在您的模块中,将子命令与全局可用命令相关联。

GlobalCommands.MyCompositeCommand.RegisterCommand(command1); GlobalCommands.MyCompositeCommand.RegisterCommand(command2); 为了提高代码的可测试性,您可以使用代理类来访问全局可用的命令并在测试中模拟该代理类。

以下代码示例显示了如何将按钮绑定到 WPF 中的命令。

执行我的复合命令

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-03-24
    • 1970-01-01
    • 1970-01-01
    • 2015-05-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多