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

标签 wpf mvvm user-controls relaycommand commandbinding

我已经建立了一个假人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:

最佳答案

如果您只是需要显示一条消息,您应该移动 ShowMessage()方法到 View 模型并使用消息服务从 View 模型类执行此操作。

如果你真的想调用一些只在 View 中定义才有意义的方法,这可以通过在 View 中实现一个接口(interface)并用这个接口(interface)注入(inject) View 模型来完成。例如,当您调用命令时:

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

View 模型对 View 一无所知,它只知道一个接口(interface),当然可以称为 IView 以外的其他名称。 .

另一种选择是使用事件聚合器或信使以糟糕耦合的方式将事件或消息从 View 模型发送到 View 。请引用this博客文章以获取有关此的更多信息。

这两种方法都没有打破 MVVM 模式。

关于wpf - 使用 MVVM 在另一个控件中执行方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52760893/

相关文章:

c# - WPF 动态绑定(bind)

wpf - 如何实现类似于 Windows Vista 的文件资源管理器中的地址位置栏(面包屑控制)?

c# - 如何将网格绑定(bind)到 WPF 中选定的 TreeView 项

c# - 响应式扩展 - 返回相同的可观察对象还是创建新的?

javascript - AngularJS 指令上有类似 DependencyProperty 的功能吗?

C# WPF 在 ShowDialog() 中进行更改后自动刷新父窗口的 DataGrid

c# - 如何验证 UserControl 的依赖属性?

c# - 行的WPF DataGrid StyleSelector

c# - 在 Windows 窗体中显示控件集合

asp.net - jQuery 和 UserControl 属性访问