我可以使用路由命令或路由事件从子视图模型到主视图模型 window 进行通信吗?

Can I communicate from child viewmodels to main window with a routed command or routed event?

我正在构建一个 MVVM WPF 应用程序,其中包含驻留在主 window 中并由其管理的自定义对话框控件。我希望能够从应用程序中的任何位置启动此对话框(例如,从属于某处某个子视图的视图模型)。

我的问题是:我可以使用冒泡的 RoutedCommand 或 RoutedEvent 以某种方式从某些子视图的视图模型中的逻辑获取主 window 并显示对话框,利用元素树和 WPF 的路由系统而不是将事物紧密耦合在一起?例如,我有一个 ViewModelBase,并且希望能够从任何地方调用 ViewModelBase.ShowDialog() 并触发主要 window.

中的对话逻辑

我觉得这可行,但我不太明白。与其他人一样,所有关于如何使用 RoutedCommand 复制粘贴菜单项的方法的文献都让我不知所措。我已经为类似的事情构建了事件聚合器,而且我知道带有消息总线的 MVVM 框架就在那里——但我想利用 WPF 内置函数而不是另一个一次性解决方案,如果有一种自然的方法的话。

编辑:明确地说,我想避免引入额外的依赖项或框架,例如 Prism。

编辑 2:使用下面 III 的回答中的想法让它工作。这是我用来连接它的确切方法:

Commands.cs: 提供静态单例命令对象。

// Static class exposing singleton RoutedCommand objects.
public static class Commands
{
    public static readonly ICommand ShowDialog = new RoutedCommand();
}

MainWindow.xaml:通过 Window.CommandBindings.

将其连接到事件处理程序
<Window xmlns:common="(namespace containing static Commands class)">
    <Window.CommandBindings>
        <CommandBinding Command="{x:Static common:Commands.ShowDialog}" Executed="ShowDialog_Executed" />
    </Window.CommandBindings>
</Window>

MainWindow.xaml.cs

public void ShowDialog_Executed(object sender, System.Windows.Input.ExecutedRoutedEventArgs e) 
{ 
    // handle command
}

ViewModelBase.cs:代表调用者启动 RoutedCommand 的代码。

protected void ShowDialog()
{
    Commands.ShowDialog.Execute(...); // Can pass dialog text through here.
}

您可以设置一个静态 class,它可以只是一个 Action,并处理任何订阅者的注册。订阅该命令的任何人都可以调用该操作。

想法是这样的..

public static class CommandManager
{
   List<ViewModel> _subscribers;

   static CommandManager()
   {
     _subscribers = new List<ViewModel>();
     ShowDialogCommand = new Action(() => window.ShowDialog()); // or do whatever you want with your child view models.
   }

   public ICommand ShowDialogCommand { get; private set; }

   public void Register(ViewModel viewModel)
   {
     _subscribers.Add(command);
   }

}

ChildViewModel

public class ChildViewModel
{
   public ChildViewModel()
   { 
      CommandManager.Register(this);
   }
}

查看

<Button Command="{x:Static CommandManager.ShowDialogCommand}"/>