【问题标题】:Is this bad MVVM practice? [closed]这是不好的 MVVM 做法吗? [关闭]
【发布时间】:2015-01-22 08:34:17
【问题描述】:

假设我想使用事件在视图模型中调用命令。这是不好的做法吗?如果是,为什么?

例子:

代码隐藏

void button1_Click(object sender, MouseEventArgs e)
{
    this.ViewModel.OnButton1Click();
}

视图模型

void OnButton1Click()
{
    // Do something
}

提前致谢。

【问题讨论】:

  • 在视图模型中调用方法是可以的,但它应该调用与该视图模型相关的操作,而不是与 UI 相关的操作。为什么你的模型会关心按钮?
  • 正如 Jeroen 所说,应该更改命名。 ViewModel 应该在 View 之前,并且方法应该有一个反映操作的名称。您可能还应该考虑将按钮绑定到 ICommand。
  • this.ViewModel 表示问题。否则,这不是错误的 MVVM,但它可能表明您的设计存在问题。 UI 逻辑在您的代码隐藏中非常好。只需将您的业务逻辑排除在外。
  • @JeroenVannevel 我的事件影响视图模型中的数据。

标签: c# wpf mvvm viewmodel code-behind


【解决方案1】:

是的,这是不好的做法,因为您直接从 View 引用 ViewModel,这意味着 ViewViewModel 之间存在依赖关系,因此紧密耦合。

该模式特别要求 View NOT 依赖于特定的 ViewModel 实例或类型。这里的想法是为多态Views 解耦ViewsViewModels(您可以通过多种方式显示相同数据的想法)。为了使您的View 可重用,它不需要对特定的ViewModel 类型有具体的依赖关系。

处理此问题的更好方法是使用 Commands,正如 Kamel 所说。但是,并非所有事件/交互/控件都必须允许调用 Commands。但是,您可以使用Blend SDK 附带的System.Windows.Interactivity.dll 程序集将Commands 附加到特定事件。

这允许您创建如下所示的 XAML:

 <i:Interaction.Triggers>
      <i:EventTrigger EventName="LostFocus">
           <i:InvokeCommandAction
               Command="{Binding UpdateTextBoxBindingOnEnterCommand}"
               CommandParameter="{Binding RelativeSource={RelativeSource FindAncestor,AncestorType={x:Type TextBox}}}"/>
       </i:EventTrigger>
  </i:Interaction.Triggers>

..它允许与事件处理程序相同的功能来调用Command,但以一种解耦的 MVVM 友好方式。

【讨论】:

  • 正如其他人所说,是的,这是不好的做法。除了在 View Constructor 中设置 DataContext 之外,不应将 ViewModel 绑定到视图。正如其他答案所建议的那样,只需实现 ICommand 接口并使用 Xaml 中的“Command={Binding}”。
【解决方案2】:

WPF 中的 MVVM 负责处理应用程序的表示逻辑和状态。这意味着视图的代码隐藏文件不应包含任何代码来处理从任何 UI 引发的事件。 所以你试图做的事情会破坏 MVVM

你应该像下面这样重写你的代码

    <Button Command="{Binding ClickCommand}" Width="100" Height="100" Content="test"/>

窗口背后的代码:

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        DataContext = new ViewModelBase();
    }
}

还有 ViewModel:

public class ViewModelBase
{
    public ViewModelBase()
    {
        _canExecute = true;
    }
    private ICommand _clickCommand;
    public ICommand ClickCommand
    {
        get
        {
            return _clickCommand ?? (_clickCommand = new CommandHandler(() => MyAction(), _canExecute));
        }
    }
    private bool _canExecute;
    public void MyAction()
    {

    }
}
public class CommandHandler : ICommand
{
    private Action _action;
    private bool _canExecute;
    public CommandHandler(Action action, bool canExecute)
    {
        _action = action;
        _canExecute = canExecute;
    }

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

    public event EventHandler CanExecuteChanged;

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-01-03
    • 1970-01-01
    • 2010-09-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多