繁体   English   中英

使用WPF MVVM模式实现接口

[英]Implement interface with WPF MVVM pattern

我想为WPF用户控件集实现一个接口(添加行为)。 我正在使用MVVM设计模式。 我应该在哪里实现该接口? 在用户控制代码中还是在View模型类中?

例如:

我的界面是

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:在此示例中,我想通过按钮的可见性来绑定(TwoWay Bind) IsLast属性。

在View模型类中实施

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

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

您应该在UserControl中实现此接口,因为它与UserControl直接相关,它与ViewModel没有关系。 视图模型用于业务逻辑以及视图和模型之间的交互。 UI / View上发生的事件不应直接在ViewModel上执行任何操作。

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

在完美世界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的外观不再重要(因为它永远都不会放在首位)。

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

当您设计MVVM应用程序时,您应该考虑层次。 模型层本身应该可用。 视图模型层应可与模型和服务一起使用。 视图将所有内容组合在一起。

但是导航呢?

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

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

将一个IsLast属性添加到ViewModel,确保它正确引发了NotifyPropertyChanged。

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

做完了

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM