C# 其他视图内的视图(WPF/MVVM)

C# 其他视图内的视图(WPF/MVVM),c#,wpf,mvvm,C#,Wpf,Mvvm,我有一个名为ControlButtonsView的用户控件 <Grid> <Button Style="{StaticResource MinimizeButton}" Command="{Binding MinimizeAppCommand}" Height="40" Width="120" VerticalAlignment="Top" HorizontalAlign

我有一个名为ControlButtonsView的用户控件

<Grid>
    <Button Style="{StaticResource MinimizeButton}" Command="{Binding MinimizeAppCommand}" Height="40" Width="120" VerticalAlignment="Top" HorizontalAlignment="Right"/>
    <Button Content="X" Style="{StaticResource ExitButton}" Command="{Binding ExitAppCommand}" Height="40" Width="60" VerticalAlignment="Top" HorizontalAlignment="Right"/>
</Grid>
在我的主窗口中.xaml.cs

this.DataContext = new AppManagerViewModel();
AppManagerViewModel控制视图之间的切换

我想要的是能够在多个其他视图中使用这个ControlButtonsView及其ControlButtonsViewModel,这个视图是一个带有最小化和最大化按钮的用户控件,我想在多个视图中,在LogInView、MenuView等中使用它们

如果有更简单的方法,请告诉我)谢谢

  • AppManagerViewModel
    中,添加
    ControlButtonsViewModel
    的属性

    公共控制按钮视图模型控制按钮视图模型{get;set;}

  • AppManagerViewModel
    的构造函数中,添加
    ControlButtonsViewModel=新的ControlButtonsViewModel()

  • AppManagerView
    的Xaml中


  • 窗口
    逻辑不属于视图模型。视图模型不关心用户界面。您必须始终假装没有UI,只有一个模型来实现视图模型

    因此,在视图模型中引用
    MainWindow
    ,将导致应用程序与视图/UI紧密耦合

    MVVM的目标是消除这种紧密耦合。显然,由于您引入的紧密耦合,您目前没有实现MVVM模式(您实现它是错误的)。
    例如,如果不创建视图,您将无法测试视图模型

    将视图作为构造函数依赖项注入会使情况变得更糟

    因为这些命令执行UI逻辑(close、minimize),所以必须从MVVM的角度将它们移动到控件-视图组件

    要使这些命令在整个视图中或相对于实际视觉树全局可用,您应将这些命令作为路由命令来执行,例如在您的
    主窗口上
    ,您希望通过命令来控制这些命令

    因为它们是静态的,所以它们可以被其他控件引用。因为它们是路由的,所以它们可以在命令目标(主窗口<代码>所属)所属的同一可视树中的任何位置使用

    在内部,该命令一旦执行,将引发一个路由事件,该事件将遍历可视化树,直到找到处理程序

    在您的情况下,
    main窗口将注册Execute和CanExecute处理程序以关闭或最小化自身

    以下示例仅实现关闭
    窗口的逻辑
    您可以按照该模式提供附加逻辑,例如最大化
    窗口

    MainWindow.xaml.cs

    partial class MainWindow : Window
    {
      public static readonly RoutedUICommand CloseWindowRoutedCommand = new RoutedUICommand(
        "Closes the application.", 
        nameof(MainWindow.CloseWindowRoutedCommand), 
        typeof(MainWindow));
    
    
      public MainWindow()
      {
        InitializeComponent();
    
        this.CommandBindings.Add(
          new CommandBinding(MainWindow.CloseWindowRoutedCommand, 
            ExecuteCloseWindow, 
            CanExecuteCloseWindow));
      }
    
      private void CanExecuteCloseWindow(object sender, CanExecuteRoutedEventArgs e) => e.CanExecute = true;
    
      private void ExecuteCloseWindow(object sender, ExecutedRoutedEventArgs e) => Close();
    }
    
    ControlButtonsView.xaml

    <Grid>
      <-- ICommand traverse visual tree until handler(s) is found -->
      <Button Content="X" Command="{x:static MainWindow.CloseWindowRoutedCommand}" />
    </Grid>
    
    
    
    “如果有更简单的方法来做这件事”:比什么更简单?您已将问题标记为MVVM。通过向视图模型添加与视图相关的逻辑,您当前违反了该模式。视图模型是一个不知道视图存在的组件:不允许将控件传递给视图模型并控制其行为。您可以将视图模型添加到控件中,例如通过设置DataContext。视图的构造函数可以请求视图模型,但不能反过来请求
    DataContext=this.DataContext=new-AppManagerViewModel()没有多大意义,是吗?你到底有什么问题?您可以将UserControl添加到任意多个其他控件中。这就像使用文本框。注意,为了提高性能,更重要的是,为了避免内存泄漏,您的绑定源(视图模型类)必须实现
    INotifyPropertyChanged
    。即使您没有引发事件,UI逻辑也必须移动到UserControl
    ControlButtonsView
    。然后,控件必须将这些命令作为路由命令来执行。由于您似乎只对控制主窗口感兴趣,因此应该将包含路由命令的逻辑移到此类中。路由命令是静态的,因此可以全局引用它们。MainWindow可以处理每个命令调用,只要该命令由一个孩子调用。我有一个UserControl视图,其中有两个按钮(最小化和退出),在该UserControl的视图模型中,我有两个用于这些按钮的命令按钮,问题是,我可以在其他视图中使用该视图,但是UserControl没有绑定到它的视图模型命令。这只允许我使用UserControl,但两个按钮的绑定找不到命令。谢谢,如果我理解正确,我不需要ViewModels作为UserControl,我计划全局多次使用,对吗?我只是照你说的做不完全是。我说不允许您处理UI逻辑或在视图模型中建立对视图的依赖关系-这样做不符合MVVM。它将引入许多您想要避免的问题,这就是您选择MVVM的原因。您可以将视图模型用于控件,但不要混淆职责。当你的视图模型可以在没有视图的情况下存在时,你就走上了一条好路。通常你会说,视图模型不知道有一个UI和一个用户。视图模型只知道模型并与模型对话。按照我向你展示的方式做确实能解决这个问题,对吗?我们将与UI相关的职责移回UI。现在UI可以处理自己的逻辑。例如,UI逻辑处理可见性、布局、外观(例如颜色)、动画和用户交互,或者通常处理控件及其行为;(哪个是UI逻辑rigt?因为它对UI有影响)在我的ViewModel中,我违反了MVVM模式,这是不正确的,我的ViewModels应该只执行数据逻辑并保存视图绑定到的变量?正确。视图模型从模型中获取数据,并通过数据绑定将其呈现给视图。视图模型不访问数据库
    <Grid>
      <-- ICommand traverse visual tree until handler(s) is found -->
      <Button Content="X" Command="{x:static MainWindow.CloseWindowRoutedCommand}" />
    </Grid>