【问题标题】:Implement interface with WPF MVVM pattern使用 WPF MVVM 模式实现接口
【发布时间】:2012-01-12 18:19:36
【问题描述】:

我想为一组 WPF 用户控件实现一个接口(添加行为)。 我正在使用 MVVM 设计模式。 我应该在哪里实现接口?在用户控件代码后面或视图模型类中?

例如:

我的界面是

interface IWizard
{
    event RoutedEventHandler MoveNext;
    event RoutedEventHandler MoveBack;
    event RoutedEventHandler Cancelled;   

    bool IsLast;
    bool IsFirst;
}

现在在其他地方我想访问实现这个接口的用户控件。

 ((IWizard)userControl).MoveNext += ...
 ((IWizard)userControl).MoveBack += ...
 ((IWizard)userControl).IsLast = true; 

等等。

在 UserControl 代码后面实现

我无法直接在视图模型中访问接口的属性/方法。我必须手动链接它们。对吧?


PS:在这个例子中,我想 Bind(TwoWay Bind) IsLast 属性与按钮的可见性。

在视图模型类中实现

我无法将用户控件作为接口对象访问。 例如:((IWizard)userControl).MoveNext += ...

使用 MVVM 设计模式在用户控件上实现接口的最佳实践是什么?

【问题讨论】:

  • 请解释您为什么要在 ViewModel 中使用视图的属性和事件,以便我们帮助您正确处理。这不是执行 MVVM 的方法。在 MVVM 中,ViewModel 对视图一无所知,除了它有一个 DataContext。
  • Erno:我稍微改变了问题。 " 在这个例子中,我想 Bind(TwoWay Bind) IsLast 属性与按钮的可见性。"

标签: c# wpf mvvm interface


【解决方案1】:

你应该在UserControl中实现这个接口,因为它与UserControl直接相关,与ViewModel无关。 View Model 用于业务逻辑以及 View 和 Model 之间的交互。 UI/View 上发生的事件不应该直接在 ViewModel 上做任何事情。

我知道您将无法直接在视图模型中访问属性,但这就是 MVVM 的用途。使用绑定和命令将 Control 中的属性和方法绑定到您的 ViewModel

【讨论】:

    【解决方案2】:

    在完美世界的 MVVM 中,ViewModel 对 View 毫无了解。从 ViewModel 的角度来看,View 是否实现了任何接口都无关紧要。

    在您的场景中,我认为更重要的是谁将响应MoveNextMoveBackCanceled 事件。最有可能的是 ViewModel。这意味着您可能可以在这些 ViewModel 中使用诸如 WizardMoved(object sender, EventArgs e) 之类的方法。看看我们在这里做了什么——ViewModel 需要对 View 有一些间接的了解。这不是一个好兆头。

    也许相反,您可以以不同的方式处理问题。也许您需要的是 IWizardMovement 接口,它将定义处理向导移动事件的方法 - 该接口将由 ViewModels 实现。这样当您将 ViewModel 传递给 View 时,它可以轻松地将 ViewModel 的处理程序订阅到它自己的事件(请注意,View 实现什么接口并不重要)。

    public interface IWizardMovementViewModel
    {
        void WizardMovedNext(object sender, EventArgs e);
        void WizardMovedBack(object sender, EventArgs e);
        void WizardMoveCanceled(object sender, EventArgs e);
    }
    

    现在,由于在 MVVM 中 View 知道 ViewModel(而不是反过来),您可以轻松地利用这些知识:

    // Wizard user control constructor
    public Wizard(IWizardMovementViewModel viewModel)
    {
        MoveNext += viewModel.WizardMovedNext;
        MoveBack += viewModel.WizardMovedBack;
        Canceled += viewModel.WizardMoveCanceled;
    }
    

    ViewModel 现在与 View 完全分离,您的 View 看起来如何不再重要(因为它不应该放在首位)。

    【讨论】:

      【解决方案3】:

      首先,您的视图模型不应该有一个名为“userControl”的字段。

      当你设计一个 MVVM 应用程序时,你应该从层的角度来考虑。模型层应该可以单独使用。 View-Model 层应该可以与模型和服务一起使用。视图将所有内容组合在一起。

      但是导航呢?

      与其让您的视图模型直接访问用户控件,不如只让它访问抽象概念的导航。在 WPF 中,这意味着 NavigationWindow.NavigationService 或 Frame.NavigationService。

      您可以在 Granite.Xaml (http://granite.codeplex.com/SourceControl/changeset/view/85060#2109525) 的 NavigationViewModel 类中看到一个示例。由于它需要一个抽象接口(在我的例子中为 INavigator,在你的例子中为 IWizard),您仍然可以使用简单的模拟技术单独测试视图模型。

      【讨论】:

        【解决方案4】:

        向 ViewModel 添加 IsLast 属性,确保它正确引发 NotifyPropertyChanged。

        使用 ValueConverter 将 Button 的 Visibility 绑定到 IsLast 属性,该 ValueConverter 将布尔值转换为 Visability 并返回。

        完成。

        【讨论】:

          猜你喜欢
          • 2010-10-03
          • 1970-01-01
          • 2017-12-06
          • 1970-01-01
          • 2013-08-16
          • 1970-01-01
          • 2011-10-11
          • 2014-08-28
          • 1970-01-01
          相关资源
          最近更新 更多