MVVM:我是否使用事件或方法调用来在ViewModel和Model之间进行通信

Tom*_*lla 0 c# wpf mvvm

这是一个设计决定,但由于我是这个项目的唯一开发人员,我没有其他人可以问.

我有一个MVVM项目,我有一个允许用户将人员添加到聚会预订的视图.有一个商业规则(和那个讨厌的"现实")说一个人不能被添加到同一个聚会的预订中.View调用RelayCommand来添加Person.

由于有添加Person的业务规则,我知道我需要调用Model.我的问题是:怎么样?

我可以在Model中调用一个方法,传递Person,如果返回true,我可以添加Person. - 或者 - 我可以订阅ViewModel的PropertyChanged,如果有人添加,请检查它们并在属性失败时清除它们.

前进的更好方法是什么?

Tse*_*eng 6

我不同意@Gigi.

ViewModel应仅包含与ViewModel/View相关的表示逻辑,例如处理验证或事件(如点击)或格式化视图的输入/输出.但是一个Person无法添加到同一方的Reservation中,可能会在所有地方强制执行,而不仅仅是在你的ViewModel中(即如果你有不同的ViewModel执行类似的操作,你必须重复你的逻辑,这是不好的).

相反,您应该有用于处理预留的服务类,其中包含相关逻辑并将此服务注入ViewModel并从那里调用它的操作.

// Implement interface, if you go for dependency injection or unit tests
public class PartyRegistrationService 
{   
    private RegistrationRepository registrationRepository;
    private PartyRepository partyRepository;
    private PersonRepository personRepository;

    // inject the repositories here, if you use DI
    public PartyRegistrationService() 
    {
        this.registrationRepository = new RegistrationRepository();
        this.personRepository = new PersonRepository();
        this.partyRepository = new PartyRepository();
    }

    public bool RegisterPersonToParty(int personId, int partyId) 
    {
        Person person = personRepository.GetById(personId);
        Party party = partyRepository.GetById(partyId);

        // invalid person or party id
        if(person==null || party==null)
            return false;

        if(registrationRepository.GetByPerson(person)!=null) 
        {
            // person has a registration already
            return false;
        }

        // person has no registration yet
        var registration = new Registration(person, party);
        registrationRepository.Save(registration);

        return true;
    }
}
Run Code Online (Sandbox Code Playgroud)

通过这种方式,您的逻辑将耦合到服务类中,并从ViewModel中调用服务RegisterPersonToParty并将ID传递给它.理想情况下,您使用an AsyncRelayCommand来避免在存储库/数据库操作期间的UI锁定.

不要在ViewModels属性中使用这种异步/昂贵/昂贵的操作!

编辑:评论的补充 取决于您是否要使用富域或贫血域(后来被许多现代开发人员劝阻),可以将某些类型的逻辑放入模型中,而将其他逻辑放入模型中则不应该.

遗忘域基本上是模型对象,它根本不包含任何或非常少的(业务)逻辑,所有逻辑都发生在服务类中.

在Rich域中,您基本上将与特定模型相关联的业务逻辑放入模型中,并使服务层保持较薄.

您的需求中的业务逻辑不应该进入某个模型.原因是,您需要的不仅仅是"人"和"派对"数据来应用规则.您还需要Resevation模型,您需要根据一种持久性存储(SQL,本地数据库,Web服务,xml等)进行验证,因此您需要访问存储库来执行此验证.

并且您不应该在模型中访问持久层表单,因为这违反了单一责任原则(一个类应该只负责一件事)并使您的模型依赖于存储库.如果使用依赖注入,那么实例化模型并将存储库注入其中将会有很多麻烦,而不会违反其他模式(即,您的核心不应该依赖于依赖注入框架,因此很难交换您的IoC/DI容器稍后).

@AsyncRelayCommand:即使您希望用户等到操作完成,您也应该使用异步操作.如果您不使用,您的UI将锁定/冻结.这是非常糟糕的用户体验.

有了AsyncRelayCommand你可以做的操作异步和禁用UI容器(变灰所有项目,并防止用户输入),而不是锁定整个应用程序.这也将阻止您的应用程序收到"应用程序未响应"消息.

应用程序无响应