简体   繁体   English

使用WPF MVVM模式实现接口

[英]Implement interface with WPF MVVM pattern

I wanna implement an interface(Add behavior) for set of WPF usercontrols. 我想为WPF用户控件集实现一个接口(添加行为)。 I'm using MVVM design pattern. 我正在使用MVVM设计模式。 Where I should implement the interface? 我应该在哪里实现该接口? in usercontrol code behind or in View model class? 在用户控制代码中还是在View模型类中?

Ex: 例如:

My Interface is 我的界面是

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

    bool IsLast;
    bool IsFirst;
}

Now in other place I wanna access user controls which are implemented this interface as this. 现在在其他地方,我想访问通过此接口实现的用户控件。

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

etc.. 等等..

Implement in UserControl Code behind 在后面的UserControl代码中实施

I can't acess the interface's properties/methods directly in view model. 我无法直接在视图模型中访问接口的属性/方法。 I have to link them manually. 我必须手动链接它们。 right ? 对 ?


PS: In this example I wanna Bind(TwoWay Bind) IsLast Property with a visibility of a button. PS:在此示例中,我想通过按钮的可见性来绑定(TwoWay Bind) IsLast属性。

Implement in View model class 在View模型类中实施

I can't access the usercontrol as a Interface object. 我无法作为界面对象访问用户控件。 ex: ((IWizard)userControl).MoveNext += ... 例如: ((IWizard)userControl).MoveNext += ...

What is the best practice on Implementing an Interface on Usercontrol with MVVM design Pattern? 使用MVVM设计模式在用户控件上实现接口的最佳实践是什么?

You should implement this interface in UserControl because it is directly related to UserControl, it has nothing to do with ViewModel. 您应该在UserControl中实现此接口,因为它与UserControl直接相关,它与ViewModel没有关系。 View Model is for business logic and interaction between View and Model. 视图模型用于业务逻辑以及视图和模型之间的交互。 Events which occurs on UI/View should not be doing anything on ViewModel directly. UI / View上发生的事件不应直接在ViewModel上执行任何操作。

I know you won't be able to access properties directly in view model but that's what MVVM is for. 我知道您将无法直接在视图模型中访问属性,但这就是MVVM的用途。 Use the bindings and commands to bind properties and methods from Control to your ViewModel 使用绑定和命令将Control的属性和方法绑定到ViewModel

In perfect-world MVVM, ViewModel has no knowledge whatsoever about View. 在完美世界MVVM中,ViewModel完全不了解View。 Whether View implements any interface at all is irrelevant from ViewModel's point of view. 从ViewModel的角度来看,View是否完全实现任何接口都是无关紧要的。

In your scenario, what I think is more important is who will respond to MoveNext , MoveBack and Canceled events. 在您的方案中,我认为更重要的是谁将响应MoveNextMoveBackCanceled事件。 Most likely, that would be ViewModel. 最有可能的是ViewModel。 What that means you probably could use methods such as WizardMoved(object sender, EventArgs e) in those ViewModels. 这意味着您可能可以在这些ViewModel中使用诸如WizardMoved(object sender, EventArgs e) Look what we've done here - ViewModel needs to have kind of indirect knowledge about View. 看看我们在这里所做的事情-ViewModel需要具有有关View的某种间接知识。 That is not a good sign. 那不是一个好兆头。

Perhaps instead, you could approach problem differently. 也许相反,您可以以不同的方式处理问题。 Maybe what you need is IWizardMovement interface that will define methods to handle wizard moving events - and this interface will be implemented by ViewModels. 也许您需要的是IWizardMovement接口,该接口将定义处理向导移动事件的方法-该接口将由ViewModels实现。 So that when you pass ViewModel to View, it can easily subscribe ViewModel's handlers to its own events (note that not it doesn't really matter what interface View implements). 这样,当您将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);
}

Now, since in MVVM View knows about ViewModel (and never the other way around), you can easily utilize this knowledge: 现在,由于MVVM中的View是关于ViewModel的(而不是其他),因此您可以轻松地利用以下知识:

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

ViewModel is separated from View for good now, and how your View looks like is not important anymore (as it should never been in first place). ViewModel现在已经从View暂时分离出来了,并且View的外观不再重要(因为它永远都不会放在首位)。

First of all, your view-model shouldn't have a field called "userControl". 首先,您的视图模型不应包含一个名为“ userControl”的字段。

When you design an MVVM application you should think in terms of layers. 当您设计MVVM应用程序时,您应该考虑层次。 The Model layer should be usable by itself. 模型层本身应该可用。 The View-Model layer shoul be usable with the Models and Services. 视图模型层应可与模型和服务一起使用。 The View is what combines everything together. 视图将所有内容组合在一起。

But what about navigation? 但是导航呢?

Rather than giving your view-model direct access to the user control, you should only give it access to the abstract notion of navigation. 与其给视图模型直接访问用户控件,不如给它访问抽象的导航概念。 In WPF that means NavigationWindow.NavigationService or Frame.NavigationService. 在WPF中,这意味着NavigationWindow.NavigationService或Frame.NavigationService。

You can see an example of this in NavigationViewModel class in Granite.Xaml (http://granite.codeplex.com/SourceControl/changeset/view/85060#2109525). 您可以在Granite.Xaml(http://granite.codeplex.com/SourceControl/changeset/view/85060#2109525)的NavigationViewModel类中查看此示例。 Since it takes an abstract interface (INavigator in my case, IWizard in yours) you can still test the view-model in isolation using simple mocking techniques. 由于它需要一个抽象接口(在我的情况下为INavigator,在您的情况下为IWizard),因此您仍然可以使用简单的模拟技术单独测试视图模型。

Add a IsLast property to the ViewModel, make sure it raises NotifyPropertyChanged correctly. 将一个IsLast属性添加到ViewModel,确保它正确引发了NotifyPropertyChanged。

Bind the Visibility of the Button to the IsLast property using a ValueConverter that converts a boolean into a Visability and back. 使用ValueConverter将Button的可见性绑定到IsLast属性,该函数将布尔值转换为Visability并返回。

Done. 做完了

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

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