wpf 使用MVVM在另一个质控品中执行方法

k5hmc34c  于 2022-12-14  发布在  其他
关注(0)|答案(1)|浏览(112)

我构建了一个虚拟的UserControl,它的代码隐藏中有一个显示消息的方法。我在主窗口中使用了这个控件,并希望在使用命令和MVVM单击Button时执行它的方法。这是一个好的设计吗?如果不是,我该如何改进它?我当前的代码如下所示:

<UserControl x:Class="ControlBining.Control1"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
             mc:Ignorable="d" 
             d:DesignHeight="450" d:DesignWidth="800">
    <Grid DataContext="{Binding RelativeSource={RelativeSource AncestorType=UserControl}}">
    </Grid>
</UserControl>

public partial class Control1 : UserControl
   {
      public Control1()
      {
         InitializeComponent();
      }

      public void ShowMessage()
      {
         MessageBox.Show("Called from other control!");
      }
   }

<Window x:Class="ControlBining.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:ControlBining"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Window.DataContext>
        <local:ViewModel/>
    </Window.DataContext>
    <StackPanel Margin="0 50 0 0">
        <local:Control1 Width="100"/>
        <Button Width="100" Content="Show Message"/>
    </StackPanel>
</Window>

   public class RelayCommand : ICommand
   {
      private readonly Predicate<object> m_canExecute;
      private readonly Action<object> m_execute;

      public RelayCommand(Predicate<object> canExecute, Action<object> execute)
      {
         m_canExecute = canExecute;
         m_execute = execute;
      }

      public event EventHandler CanExecuteChanged
      {
         add => CommandManager.RequerySuggested += value;
         remove => CommandManager.RequerySuggested -= value;
      }

      public bool CanExecute(object parameter)
      {
         return m_canExecute(parameter);
      }

      public void Execute(object parameter)
      {
         m_execute(parameter);
      }
   }

目前,我已经使用以下代码使其工作,但我不确定这是否是一个好的设计:

private void Control1_Loaded(object sender, RoutedEventArgs e)
  {

     ViewModel m = (ViewModel)DataContext;
     m.ShowMessage += M_ShowMessage;
  }

  private void M_ShowMessage()
  {
     ShowMessage();
  }

  public event Action ShowMessage;

  private ICommand m_showMessageCommand;
  public ICommand ShowMessageCommand
  {
     get
     {
        return m_showMessageCommand ?? (m_showMessageCommand = new RelayCommand(
                  p => true,
                  p => ShowMessage?.Invoke()));
     }
  }
wwwo4jvm

wwwo4jvm1#

如果只需要显示一条消息,则应该将ShowMessage()方法移到视图模型中,并使用消息服务从视图模型类中完成此操作。
如果你真的想调用某个只有在视图中定义才有意义的方法,可以通过在视图中实现一个接口,并将这个接口注入视图模型来实现,例如当你调用命令时:

public interface IView
{
    void ShowMessage();
}

public partial class Control1 : UserControl, IView
{
    public Control1()
    {
        InitializeComponent();
    }

    public void ShowMessage()
    {
        MessageBox.Show("Called from other control!");
    }
}

查看型号:

public ICommand ShowMessageCommand
{
    get
    {
        return m_showMessageCommand ?? (m_showMessageCommand = new RelayCommand(
                  p => true,
                  p =>
                  {
                      IView view as IView;
                      if (view != null)
                      {
                          //...
                          view.ShowMessage();
                      }
                  }));
    }
}

视图模型对视图一无所知,它只知道一个接口,这个接口当然可以被称为IView以外的其他名称。
另一种选择是使用事件聚合器或消息发送器,以一种松散耦合的方式将事件或消息从视图模型发送到视图,请参考this博客文章了解更多信息。
这两种方法都没有打破MVVM模式。

相关问题