代码之家  ›  专栏  ›  技术社区  ›  Vahid

使用MVVM在另一个控件中执行方法

  •  1
  • Vahid  · 技术社区  · 6 年前

    我造了个假人 UserControl 它的代码中有一个显示消息的方法!我在我的主窗口中使用了这个控件,当我单击一个 Button 使用命令和MVVM。我该怎么做?

    <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>
    

    C#:

    public partial class Control1 : UserControl
       {
          public Control1()
          {
             InitializeComponent();
          }
    
          public void ShowMessage()
          {
             MessageBox.Show("Called from other control!");
          }
       }
    

    主窗口XAML:

    <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();
      }
    

    在ViewModel中

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

    XAML编号:

    1 回复  |  直到 6 年前
        1
  •  1
  •   mm8    6 年前

    如果您只是需要显示一条消息,您应该移动 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模式。