C# MVVM:ViewModel 和业务逻辑连接
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/16338536/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
MVVM: ViewModel and Business Logic Connection
提问by JDeuker
After doing a few Projects using the MVVM Pattern, Im still struggling with the Role of the ViewModel:
在使用 MVVM 模式做了几个项目之后,我仍然在为 ViewModel 的角色而苦苦挣扎:
What I did in the past: Using the Model only as a Data Container. Putting the Logic to manipulate the Data in the ViewModel. (Thats the Business Logic right?) Con: Logic is not reusable.
我过去所做的:仅将模型用作数据容器。将逻辑放在 ViewModel 中来操作数据。(这就是业务逻辑吧?) 缺点:逻辑不可重用。
What I'm trying now: Keeping the ViewModel as thin as possible. Moving all Logic into the Model Layer. Only keeping presentation Logic in the ViewModel. Con: Makes UI Notification realy painful If Data is Changed inside the Model Layer.
我现在正在尝试的是:保持 ViewModel 尽可能薄。将所有逻辑移动到模型层。仅在 ViewModel 中保留表示逻辑。缺点:如果模型层内的数据发生变化,UI 通知会非常痛苦。
So I will give you an Example to make it more clearer:
所以我会给你一个例子,让你更清楚:
Scenario: Tool to Rename Files. Classes: File : Representing each File; Rule: Contains Logic how to Rename a File;
场景:重命名文件的工具。类: File :代表每个文件;规则:包含如何重命名文件的逻辑;
If Im following approach 1: Creating a ViewModel for File, Rule and the View -> RenamerViewModel. Putting all Logic in the RenamerViewModel: Containing a List of FileViewModel and RuleViewModel and the proceeding Logic. Easy and fast, but not reusable.
如果我遵循方法 1:为文件、规则和视图创建一个 ViewModel -> RenamerViewModel。将所有逻辑放在 RenamerViewModel 中:包含 FileViewModel 和 RuleViewModel 以及处理逻辑的列表。简单快捷,但不可重复使用。
If Im following approach 2: Creating a new Model Class -> Renamer, which contains a List of File, Rule und the proceeding Logic to interate over each File and apply each Rule. Creating a Viewmodel for File, Rule and Renamer. Now the RenamerViewModel only contains an instance of Renamer Model, plus two ObservableCollections to wrap the File und Rule List of the Renamer. But the whole Logic is in the Renamer Model. So if the Renamer Model is triggered to manipulate some Data by Method Calls, the ViewModel has no Clue which Data is manipulated. Because the Model doesnt Contain any PropertyChange Notification and I will avoid that. So the Business and Presentation Logic is seperated, but this makes it hard to notify the UI.
如果我遵循方法 2:创建一个新的模型类 -> 重命名器,其中包含文件列表、规则和处理逻辑以交互每个文件并应用每个规则。为文件、规则和重命名器创建视图模型。现在 RenamerViewModel 只包含一个 Renamer Model 的实例,加上两个 ObservableCollections 来包装 Renamer 的 File 和 Rule List。但是整个逻辑都在 Renamer 模型中。所以如果Renamer Model 被方法调用触发去操作一些Data,ViewModel 就没有线索去操作哪些Data。因为模型不包含任何 PropertyChange 通知,我会避免这种情况。所以业务和呈现逻辑是分开的,但这使得通知 UI 变得困难。
采纳答案by Jon
Putting business logic inside the viewmodel is a very bad way to do things, so I 'm going to quickly say never do thatand move on to discussing the second option.
将业务逻辑放在视图模型中是一种非常糟糕的做事方式,所以我将很快说永远不要这样做,然后继续讨论第二个选项。
Putting the logic inside the model is much more reasonable and it's a fine starting approach. What are the drawbacks? Your question says
将逻辑放在模型中更合理,这是一个很好的开始方法。有什么缺点?你的问题说
So if the Renamer Model is triggered to manipulate some Data by Method Calls, the ViewModel has no Clue which Data is manipulated. Because the Model doesnt Contain any PropertyChange Notification and I will avoid that.
所以如果Renamer Model 被方法调用触发去操作一些Data,ViewModel 就没有线索去操作哪些Data。因为模型不包含任何 PropertyChange 通知,我会避免这种情况。
Well, making your model implement INotifyPropertyChangedwould certainly let you move on to better things. However, it's true that sometimes it is not possible to do that -- for example the model may be a partial class where properties are auto-generated by a tool and don't raise change notifications. That's unfortunate, but not the end of the world.
好吧,让你的模型实现INotifyPropertyChanged肯定会让你继续做更好的事情。但是,确实有时无法做到这一点——例如,模型可能是一个部分类,其中的属性由工具自动生成并且不会引发更改通知。这是不幸的,但不是世界末日。
If you want to buy something then someonehas to pay for it; if it's not the model that gives such notifications then you are left with only two choices:
如果你想买东西,那么就必须有人付钱;如果不是提供此类通知的模型,那么您只有两种选择:
- The viewmodel knows which operations on the model (possibly) cause changes and it updates its state after each such operation.
- Someone else knows which operations cause changes and they notify the viewmodel to update its state after the model it is wrapping changes.
- 视图模型知道模型上的哪些操作(可能)会导致更改,并在每次此类操作后更新其状态。
- 其他人知道哪些操作会导致更改,并且他们会在包装更改的模型之后通知视图模型更新其状态。
The first option is again a bad idea, because in effect it is going back to putting "business logic" inside the viewmodel. Not as bad as putting allthe business logic in the viewmodel, but still.
第一个选项再次是一个坏主意,因为实际上它正在返回将“业务逻辑”放入视图模型中。不像将所有业务逻辑放在视图模型中那么糟糕,但仍然如此。
The second option is more promising (and unfortunately more work to implement):
第二种选择更有希望(不幸的是,还有更多的工作要做):
- Put part of your business logic in a separate class (a "service"). The service will implement all business operations you will want to perform by working with model instances as appropriate.
- This means that the service knows when model properties may change (this is OK: model + service == business logic).
- The service will provide notifications about changed models to all interested parties; your viewmodels will take a dependency on the service and receive these notifications (so they will know when "their" model has been updated).
- Since the business operations are also implemented by the service, this remains very natural (e.g. when a command is invoked on the viewmodel the reaction is calling an appropriate method on the service; remember, the viewmodel itself does not know about the business logic).
- 将部分业务逻辑放在单独的类(“服务”)中。该服务将通过适当地使用模型实例来实现您想要执行的所有业务操作。
- 这意味着服务知道模型属性何时可能发生变化(这是可以的:模型 + 服务 == 业务逻辑)。
- 该服务将向所有相关方提供有关更改模型的通知;您的视图模型将依赖于服务并接收这些通知(因此他们将知道“他们的”模型何时更新)。
- 由于业务操作也由服务实现,这仍然很自然(例如,当在视图模型上调用命令时,反应正在调用服务上的适当方法;记住,视图模型本身不知道业务逻辑)。
For more information on such an implementation see also my answers hereand here.
回答by Kent Boogaart
Both approaches are valid, but there is a third approach: implement a service between the model and VM layers. If you want to keep your models dumb, a service can provide a UI-agnostic middleman that can enforce your business rules in a re-usable fashion.
这两种方法都是有效的,但还有第三种方法:在模型层和 VM 层之间实现服务。如果你想让你的模型保持愚蠢,服务可以提供一个与 UI 无关的中间人,它可以以可重用的方式执行你的业务规则。
Because the Model doesnt Contain any PropertyChange Notification and I will avoid that
因为模型不包含任何 PropertyChange 通知,我会避免这种情况
Why are you avoiding this? Don't get me wrong, I tend to keep my models as dumb as possible, but implementing change notification in your model can sometimes be useful, and you take a dependency only on System.ComponentModelwhen you do. It's completely UI agnostic.
你为什么要避免这个?不要误会我的意思,我倾向于让我的模型尽可能保持愚蠢,但是在模型中实现更改通知有时会很有用,并且您只依赖于System.ComponentModel何时这样做。它完全与 UI 无关。
回答by Rafael A. M. S.
You can also implement IDataErrorInfo on both: Model and ViewModel, but doing the validation only in Model, this will ease your way in implementing the business rules only at Model ...
您还可以同时在 Model 和 ViewModel 上实现 IDataErrorInfo,但仅在 Model 中进行验证,这将简化您仅在 Model ...
Ex:
前任:
ViewModel:
视图模型:
...
private Person person;
...
string IDataErrorInfo.this[string propertyName]
{
get
{
string error = (person as IDataErrorInfo)[propertyName];
return error;
}
}
Model:
模型:
public class Person:INotifyPropertyChanged,IDataErrorInfo
{
...
string IDataErrorInfo.this[string propertyName]
{
get { return this.GetValidationError(propertyName); }
}
...
string GetValidationError(string propertyName)
{
if(propertyName == "PersonName")
//do the validation here returning the string error
}
}
Plus take a look at the MVCVM Pattern, im actually using it and it is pretty fine to abstract the business logic to a controller class instead of the model or viewmodel
另外看看MVCVM模式,我实际上正在使用它并且将业务逻辑抽象到控制器类而不是模型或视图模型是非常好的
回答by rolls
I do the following
我做以下
View with XAML view logic only
ViewModel which handles click handlers and creating new view models. Handles routed events etc.
Model which is my data container and business logic regarding validating the model data.
Services which populate the model with data. Eg call a web server, load it from disk, save to disk etc. Depending on the example often both my model and service will implement IPropertyChanged. Or they may have event handlers instead.
仅使用 XAML 视图逻辑查看
ViewModel 处理点击处理程序和创建新的视图模型。处理路由事件等。
模型是我的数据容器和关于验证模型数据的业务逻辑。
用数据填充模型的服务。例如,调用 Web 服务器、从磁盘加载它、保存到磁盘等。根据示例,我的模型和服务通常都将实现 IPropertyChanged。或者他们可能有事件处理程序。
Any complex application imo needs another layer. I call it model + service, view, viewmodel. The service abstracts your business logic and takes a model instance as a dependency or creates a model.
任何复杂的应用程序 imo 都需要另一层。我称之为模型 + 服务、视图、视图模型。该服务抽象您的业务逻辑并将模型实例作为依赖项或创建模型。

