关于mvvm:多窗口WPF应用程序中的命令绑定

Command binding in multiwindow WPF app

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

1
2
3
4
5
6
7
public static class Commands
{
    public static readonly RoutedCommand EntityEditRequest = new RoutedCommand();
    public static  RelayCommand EntityEditorChangeRequest;
    public static RelayCommand XMLUpdateRequest;
    public static RelayCommand SaveRequest;  
}

用户控件的每个viewmodel将在构造函数中执行类似的操作

1
2
3
4
5
 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时,在加载每个新窗口时,会将静态命令设置为新绑定。

Window打开的窗口视图模型构造函数将静态命令绑定设置为其对象命令处理程序。窗口A处于活动状态。命令就可以了。

窗口B加载窗口B视图模型构造函数将静态命令绑定设置为其对象命令处理程序。窗口B处于活动状态。命令就可以了。

现在,用户选择"窗口A"选项卡以将窗口A设置为活动状态。指挥将无法工作。当然,因为Command绑定到Window B命令处理程序,所以不会。

从理论上讲,静态命令可以处理该方案,因为在任何给定点上只有一个活动窗口。但是如何??


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

1
  public static CompositeCommand SaveCommand = new CompositeCommand();

然后可以在整个ViewModel或类似的地方访问该命令...

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

然后可以利用IActiveAware接口定义哪个Window是活动的Window并相应地对命令进行操作。

在创建全局可用命令方面,也有一个MSDN发布。不要忘记注销该命令,以避免内存泄漏。


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

特定于视图的命令应在视图模型上定义,
作为DataContext传递以查看,从而实现单独的实现
对于具有不同视图模型的不同视图,
或至少让视图传递了CommandParameter
可以用来标识它们(例如对视图的引用)或它们的DataContext。

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


您为什么决定将其放入静态类的任何原因?

1
2
3
4
5
6
7
8
9
class XMLEditorViewModel
{
    public ICommand SaveRequest { get; private set; }

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


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

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

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

下面的代码示例演示如何将按钮绑定到WPF中的命令。

执行我的复合命令