This question already has answers here:
MVVM in WPF - How to alert ViewModel of changes in Model... or should I?
(11 answers)
Closed 5 years ago.
Based on the picture from MSDN
It seems like all the data and business logic should be inside Model where View Model should have a duplicated set of properties of the Model for display purposes. And View should bind to the duplicated property inside the ViewModel instead of binding to the properties inside Models directly.
ViewModel should implements INotifyPropertyChanged interface to let View know if certain property is changed.
But how should Model notify ViewModel about changes? Should it implement INotifyPropertyChanged as well? If so then we could just have the View bind to the Model's property directly. Whats the real benefit of having an extra layer in between and we have to manually handle all the data changed notifications?
example based on my understanding:
View:
<Grid>
<TextBlock Text="{Binding foo}"/>
<Label Content="{Binding bar}"/>
</Grid>
View Model:
class ViewModel : INotifyPropertyChanged
{
Model _m;
public ViewModel(Model m)
{
_m = m;
}
public string foo
{
get
{
return _m.foo;
}
set
{
_m.UpdateFoo(value);
//This one works fine. xaml will call getter to get the dead beef version
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("foo"));
}
}
public string bar
{
get
{
return _m.bar;
}
}
public event PropertyChangedEventHandler PropertyChanged;
}
Model:
class Model
{
public string foo { get; private set; }
public string bar { get; private set; }
public void UpdateFoo(string newVal)
{
foo = newVal + "dead beef";
bar = newVal; //how do i tell ViewModel that i have changed?
}
}
Notifications can come from the model via INotifyPropertyChanged; but realistically that interface is horrible to consume manually. Having to base your logic based off the name of the changed property is not fun.
A model layer with notifications could be something like a message bus client, as messages come in it parses it and sends relevant (and strongly typed) events to the view model. The view model then updates properties on its data objects that raise PropertyChanged.
To your bigger question: Do you have to have separate ViewModel and Model data objects?
NO
If you want to be a purist, sure; duplicate your objects. If you want a rational approach, only have special view model objects if you need to add properties that wouldn't be appropriate (or just cant exist on) a model object.
The model is much more about separation of concerns than a useless set of duplicate objects. In the previous example, the ViewModel should not care that the objects or events came from a message bus, it just knows how to set up the objects for the view. The Model handles the implementation detail of being a message bus client.
Related
I'm trying to learn on MVVM. I've understand the concept, however, i'm confused about the binding. I'm not sure where to bind my Fill property. Please help. Tqvm in advanced.
View - name: MainScreen.xaml
<Path Fill="{Binding mainScreenClass, Converter={StaticResource colorConverter}}"/>
inCodeBehind
DataContext = new vmMainScreen();
ViewModel - name:vmMainScreen
public ICommand cmdMouseEnterNav { get; private set; }
public mMainScreen mainScreenClass { get; set; }
public vmMainScreen()
{
mainScreenClass = new mMainScreen();
mainScreenClass.propNaviconFill = new SolidColorBrush(Colors.White);
naviconMouseEventChecker();
}
private void naviconMouseEventChecker()
{
cmdMouseEnterNav = new SimpleCommand
{
ExecuteDelegate = x => mainScreenClass.propNaviconFill = (SolidColorBrush)(new BrushConverter().ConvertFrom("#c5a02b"))
};
}
Model - name:mMainScreen
public class mMainScreen : INotifyPropertyChanged
{
private Brush _NaviconFill = new SolidColorBrush(Colors.White);
public Brush propNaviconFill
{
get
{
return this._NaviconFill;
}
set
{
this._NaviconFill = value;
NotifyPropertyChanged("propNaviconFill");
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(string info)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(info));
}
}
}
I understand that when i breakpoint on my colorConverter, I'm getting the class. Not the property of propNaviconFill. If i create another property with the Brush class on my ViewModel and bind it to Fill, there is no problem. But that means I'm not following the correct structure of MVVM. Thanks again.
You should bind to the property of your view model.
<Path Fill="{Binding propNaviconFill, Converter={StaticResource colorConverter}}"/>
Use the view model implementing the INotifyPropertyChanged as the data context of your view.
DataContext = new mMainScreen();
If you really want to use vmMainScreen as your data context, then vmMainScreen should implement INotifyPropertyChanged there and you should study how NotifyPropertyChanged was used to notify the view that the view model property has changed.
Keep in mind there are two basic types of MVVM:
1. View First
2. View Model First
Based on your example you are trying to do View First. This is easier to implement but comes with drawbacks on larger projects since the view controls the creation of the ViewModel it's harder to inject data or state into the ViewModel.
For all MVVM patterns you have the three parts:
Model - Basically a state bag. This thing is just like a customer class which most of the time implements INotifyProperty changed.
ViewModel - This is like the controller class in MVC. It has all the real logic and does the work.
View - This is your XAML and it only holds presentation logic. The code-behind class ie: MyWindow.xaml.cs should not be used except to setup the ViewModel if your going View First. (there are exceptions of course but generally it should basically be empty)
For View First
Your Window (or control) should create the ViewModel in the constructor and assign it to the DataContext.
Your ViewModel will have ICommand's, ObservableCollections and such that can be bound to controls in the View. So when your constructor fires you fill up your data and put it into the necessary structures; because of databinding this gets related to the View and shown.
Your Model (you usually have more than one, can have Customer, Order, StockTicker or whatever.) These are created by the ViewModel and put into things such as ObservableCollections for the View to databind to.
I've been looking in the MVP pattern for a while, and managed to create some simple MVP-compliant applications.
I am now trying to apply the pattern to a more complex application, and I have some doubts on the best way of doing that.
My application has a single WinForm, with two buttons for loading two different kinds of data. My view interface looks like the following:
interface IView_MainForm
{
// Load input
//
event EventHandler<InputLoadEventArgs> LoadInput_01;
event EventHandler<InputLoadEventArgs> LoadInput_02;
bool Input01_Loaded { get; set; }
bool Input02_Loaded { get; set; }
}
The IView is referenced in my presenter via constructor injection:
public Presenter_MainForm(IView_MainForm view)
{
this.View = view;
this.View.LoadInput_01 += new EventHandler<InputLoadEventArgs>(OnLoadInput_01);
this.View.LoadInput_02 += new EventHandler<InputLoadEventArgs>(OnLoadInput_02);
}
So far, so good. When the user clicks any of the two buttons for loading data, a LoadInput_## event is raised, the Presenter is handling it, checks the input for errors and structures it according to my data model.
My next step would be displaying the processed data back in the View.
I'm striving to keep my View as passive and "dumb" as possible, assuming it knows nothing of the Presenter (it doesn't subscribe to its events, the Presenter sends data to the View by calling IView methods instead), let alone of the Model.
How am I supposed to populate a control like a TreeView, if the View has no idea of what the data model looks like?
Also, am I getting the whole MVP thing right, or is there anything I have missed?
There is nothing wrong with having complex type properties in your View. Let's say you have some ComplexType.
class ComplexType
{
public string ParentNode {get;set;}
public List<string> ChildNodes {get;set;}
// some other properties
}
Let's also assume ComplexType is data model for your TreeView. It is perfectly fine with MVP pattern to have properties on your View that will have ComplexType. So having something like this is perfectly fine
interface IView_MainForm
{
// Load input
//
event EventHandler<InputLoadEventArgs> LoadInput_01;
event EventHandler<InputLoadEventArgs> LoadInput_02;
bool Input01_Loaded { get; set; }
bool Input02_Loaded { get; set; }
ComplexType Input01Data {get;set;} // you might actually have some code in get/set setters
ComplexType Input02Data {get;set;} // you might actually have some code in get/set setters
public void SetInput01Data(ComplexType input01Data)
{
Input01Data = input01Data;
// some other stuff
}
}
And since your Model is for View that has 2 inputs, your Model could look something like this
public interface IModel
{
public ComplexType Input01Data {get;set;}
public ComplexType Input02Data {get;set;}
}
Now in your Presenter you would just handle event fired from View, populate Model and set properties on View
class Presenter
{
private IModel _myModel...
private IRepository _repository;
public Presenter(IView_MainForm view, IRepository repository)
{
_repository = repository;
this.View = view;
this.View.LoadInput_01 += new EventHandler<InputLoadEventArgs>(OnLoadInput_01);
this.View.LoadInput_02 += new EventHandler<InputLoadEventArgs>(OnLoadInput_02);
}
public void OnLoadInput_01(object sender, InputLoadEventArgs e)
{
// get data based on passed arguments (e.SomeProperty)
// construct IModel
myModel = _repository.GetData(e.SomeProperty);
// pass data to IView_MainForm
View.SetInput01Data(myModel.Input01Data);
}
}
And regarding your concern
I'm striving to keep my View as passive and "dumb" as possible,
assuming it knows nothing of the Presenter (it doesn't subscribe to
its events, the Presenter sends data to the View by calling IView
methods instead), let alone of the Model.
Your View still doesn't know anything about Presenter nor Model. It just fires events, get data from Presenter and binds its controls. And you have testability in place (please note this Unit Test is pseudo code, since I don't know how you retrieve data, what input you required in button click event etc...) .
[Test]
public void ShouldLoadInput01DataOnButtonClick()
{
// Arrange
IModel data = // create dummy data
Mock<IView_MainForm> clientsViewMock = new Mock<IView_MainForm>();
Mock<IRepository> clientsRepositoryMock = new Mock<IRepository>();
clientsRepositoryMock.Setup(repository => repository.GetData(something)).Returns(data.Input01Data);
var presenter = new Presenter(clientsViewMock.Object, clientsRepositoryMock .Object);
// Act
clientsViewMock.Raise(view => view.LoadInput01 += null, new InputLoadEventArgs());
// Assert
clientsViewMock.Verify(view => view.SetInput01Data(data.Input01Data), "Input01 data expected be set on button click.");
}
I am trying to come up with a good way of implementing the MVVM pattern using Entity-Framework where my entities are my models. My DataContext is my viewmodel. This is a small reproduction of the problem.
View
<TextBox Text="{Binding MyText}" />
ViewModel:
I have the requirement of needing to navigate record by record from my DB. When a button is clicked in the View a command is sent to the Viewmodel that executes nextRecord(). EF does its magic and _myObject is the next row/record from the database
public class myViewModel: INotifyPropertyChanged
{
private MyEntityObject _myObject;
public string MyText
{
get { return _myObject.MyText; }
set
{
if (_myObject.MyText != value)
{
_myObject.MyText = value;
OnPropertyChanged("MyText");
}
}
}
private void _nextRecord()
{
_myObject = myEntitiesContext.NextRecord() //pseudocode
}
}
Autogenerated Entity Model
public partial class MyEntityObject
{
public string MyText { get; set; }
}
Since the View has no knowledge of _myObject changing, it doesn't update when _myObject changes. A few approaches I have thought of.
I haven't tested wrapping my entities in a INotifyPropertyChanged wrapper class but am wary to do this as I have a lot of entity objects.
I could call OnPropertyChanged("...") for all properties, but some of my entities have a lot of properties to them, which would be ugly. Possible to use reflection to make it cleaner, but I may have properties that aren't databound.
I might be able to defer this to the UI, somehow refreshing the bindings when I click "Next Record", but this breaks MVVM and looks dirty
How can I get the UI to recognize changes from _myObject?
As I've mentioned in the comments, calling OnPropertyChanged("") or OnPropertyChanged(null) invalidates all properties and is equivalent to calling OnPropertyChanged for each and every property. This behavior is also documented here:
The PropertyChanged event can indicate all properties on the object
have changed by using either null or String.Empty as the property name
in the PropertyChangedEventArgs.
This means that you can simply add a call to OnPropertyChanged("") when you update your object to force WPF to reevaluate all bindings to your view model:
private void _nextRecord()
{
_myObject = myEntitiesContext.NextRecord();
OnPropertyChanged("");
}
That being said, I'd still go with #Anand's solution (+1). There's an ongoing debate on whether it's OK or not for the viewmodel to expose the model as a property, and I tend to go with exposing it until you need to introduce some view model specific logic. Most of the time you won't have to and it's not worth the trouble of wrapping model properties.
The problem with your code is that when _myObject changes the MyText property changed event is not fired. A work around would be to create a new property to hold you entity
and make this property as your Grids DataContext in your view as shown below. Now when this line is executed MyObject = myEntitiesObject.NextRecord() your view will be notified about the change.
public class myViewModel : INotifyPropertyChanged
{
private MyEntityObject _myObject;
public MyEntityObject MyObject
{
get { return _myObject; }
set {
if (_myObject != value)
{
_myObject = value;
OnPropertyChanged("MyObject");
}
}
}
private void _nextRecord()
{
MyObject = myEntitiesObject.NextRecord() //pseudocode
}
}
View:
<Grid DataContext="{Binding MyObject}">
<TextBlock Text="{Binding MyText}"/>
</Grid>
An extremely simple but not very elegant solution that I believe would meet needs: upon switching records, set the DataContext to null, then back to the ViewModel.
However, there are arguably more elegant alternatives that require more work to meet all requirements. See Anand's answer for an improvement upon this.
The tag in View should have the mode and UpdateSourceTrigger attribute set with values.
It's a simple question and I searched the Internet for hours without success...
I have a model and a view model with one property. To make this property viewable in the view, I use a view-model-object which should automatically be generated from the model-object and vice versa. Of course, the following code will throw an StackOverflowException, because the updating of the model-object in the model causes an update of the view-model-object in the view-model and this causes an update of the model-object in the model and so on...
class ModelObject
{
...
}
class ViewModelObject
{
...
}
class Model : INotifyPropertyChanged
{
private ModelObject modelObject = new ModelObject();
...
public ModelObject ModelObject
{
get
{
return this.modelObject;
}
set
{
this.modelObject = value;
this.NotifyPropertyChanged("ModelObject");
}
}
}
class ViewModel : INotifyPropertyChanged
{
private ViewModelObject viewModelObject = new ViewModelObject();
private Model model = new Model();
...
public ViewModel()
{
this.model.PropertyChanged += new PropertyChangedEventHandler(this.propertyChangedEvent);
}
public ViewModelObject ViewModelObject
{
get
{
return this.viewModelObject;
}
set
{
this.viewModelObject = value;
this.model.ModelObject = new ModelObject(...);
this.NotifyPropertyChanged("ViewModelObject");
}
}
private void propertyChangedEvent(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName.Equals("ModelObject"))
{
this.ViewModelObject = new ViewModelObject(...);
}
}
}
What is the common way to synchronize these two objects?
There is no silver bullet. As model is a representation of the database and viewmodel is more closer to the interface, there is always some business logic needed to convert the model to view model and vice versa.
I usually have two methods in my view model class - SyncModel(ViewModel viewModel) and SyncViewModel(Model model)
One more suggestion -
Model should not implement INotifyPropertyChanged. The view model should implement this as its bound to the user interface. Why does the model ever need to change? It represents whats in the db. You can refresh it but why do you need change notifications for the model?
Edit: MVVM: Binding to Model while keeping Model in sync with a server version
Hard reference. Each class having a reference to another, listens to property change event and updates itself accordingly.
Observer Pattern - Have an observer class, each class register itself with an observer, observer listens for any changes and updates all its subscribers.
There's also an event aggregator which might be useful.
If you want a deferred update, an isDirty property would be required. You know your application better, google for more articles and choose wisely.
I have read several articles, tutorials and blog posts about the MVVM pattern. However there is one thing I don't understand. Taking the three "layers":
Model
View
View Model
As far as I have understood MVVM the model contains the "raw" data, e.g. a name and address in case of a Student class. The view model exposes properties to the view which represent data of the model.
Example for a property in the view model
public string Name {
get { return model.Name; }
set { model.Name = value; }
}
Example for the model
private string name;
public string Name {
get { return name; }
set { name = value; }
}
This might sound a bit stupid but doesn't this create a redundancy? Why do I have to keep the name in the model and in the view model? Why should one not handle the name on the view model completely?
In such a simple example, this answer would be yes (it is unreasonably redundant). But, presumably, a page will contain more than just a single Model object. You may have the page state as well as multiple other Model objects which must all be tracked. This is done in the ViewModel.
For example, you may have additional information about the logged in user displayed in a status bar, as well as a service running to detect changes to a text file.
You may also have a form for editing the Student object. If you intend to validate those changes, then you wouldn't want to directly edit the Student object until after the modifications have been verified. The ViewModel can act as a temporary storage location in such a case.
Note on the above: It is not uncommon for validation to occur in the Model, but even then you will probably want the user to be able to enter invalid values while in the process of editing a form. For example, if your Model does not allow a zero-length value in a field, you still want to enable your user to delete the value, move to another field (say, for example, to copy it) then return to the field and finish editing (paste). If you are tied directly to the Model, then your validation logic may not handle this "in-between", "not-yet-finished" state as you'd like. For example, you might not want to accost your user with validation errors until they've finished and clicked 'Save'.
You will also probably have Command objects in the ViewModel to handle button clicks and the like. These would be domain-specific objects that would be useless in a Model.
ViewModels are also useful when you need to filter or somehow temporarily "modify" Model objects to get something useful on the screen. For example, you may want to display a list of all the Users in a system along with a real-time list of the top ten performers among them (updated every 10 seconds). Or you may want to show a list of Reports and a graph showing the overall usage rate, etc. Filtering, sorting and customizing that data would take place within the ViewModel.
The Model, on the other hand, is typically as pure as possible. Ideally, you want only POCOs that (usually) model exactly what's in your persistent storage (database, or what have you). If your persistent storage has FirstName and LastName fields, then so would your Model. Only in your ViewModel would you combine them to get a Name field (either "First Last" or "Last, First" depending on the View's needs).
For example:
namespace Model
{
public class Student
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
public class Class
{
public string Name { get; set; }
public float Score { get; set; }
}
}
namespace ViewModel
{
public class EditStudentRecordViewModel
{
private Model.Student _student;
private IEnumerable<Model.Class> _studentClasses;
/* Bind your View to these fields: */
public string FullName
{
return _student.LastName + ", " + _student.FirstName;
}
public string FirstName { get; set; }
public string LastName { get; set; }
public IEnumerable<Model.Class> PassingClasses
{
get
{
return _studentClasses.Where( c => c.Score >= 78 );
}
}
public IEnumerable<Model.Class> FailingClasses
{
get
{
return _studentClasses.Where( c => c.Score < 78 );
}
}
public void Save()
{
List<string> l_validationErrors = new List<string>();
if ( string.IsNullOrEmpty( this.FirstName ) )
l_validationErrors.Add( "First Name must not be empty." );
if ( string.IsNullOrEmpty( this.LastName ) )
l_validationErrors.Add( "Last Name must not be empty." );
if ( l_validationErrors.Any() )
return;
_student.FirstName = this.FirstName;
_student.LastName = this.LastName;
Model.Utilities.SaveStudent( _student );
}
}
}
The model is the object graph that contains your business logic.
That's where you hold the behaviour (validation, calculation and such).
The ViewModel is something that models the UI and its interactions.
These are different and have different reasons for existing - the point of the pattern is to separate your display logic to the VVM (View and ViewModel) and have your business logic completely separated.
The view model is where you would keep track of properties that are specific to the view and not necessary to the model.
Let's take your model, assume it's called Person.
And then you create a view model for Person called PersonViewModel, which looks like this:
public class PersonViewModel
{
public Person Person { get; set; }
}
(Note, you might not want to expose the model like this directly, but that's another story)
Now let's say that you have an button in the view which is used to save the Person instance. To provide a better user experience (UX), you want to enable the button only if your model has actually changed. So you implement the INotifyPropertyChanged interface on the Person class:
public class Person : INotifyPropertyChanged
{
...
Now, you could expose a HasUnsavedChanges property from your Person which the Enabled property on the save button would bind to, but that logic has nothing to do with the person.
This is where the view model comes in. You would define this view-specific property on the view model, like so:
public class PersonViewModel
{
public Person Person { get; set; }
public bool HasUnsavedChanges { get; set; }
}
Then, your view model would subscribe to the PropertyChanged event of the INotifyPropertyChanged interface, and toggle the HasUnsavedChanges property on the view model.
Then, if the binding is set up correctly, the save button would enable/disable when any change happens on your model, but your model doesn't have any logic tying it to the view.
Note that you'd have to also implement INotifyPropertyChanged on the view model as well for your view to pick up when changes are made to the view model it is bound to.
Again, the point is acting as a bridge to contain the logic that is a combination of model properties and view properties that don't belong on the model.
Model in MVVM is exactly the same as in MVP or Model2 MVC. It is the one part of MVC-inspired patterns that is not affected by variations on the theme.
Model is the layer which contains repositories, units of work, domain/model objects, data mappers, services and some other structures. All they combined create the model layer, which contains all of the domain business logic for the particular application.
Model is not any single instance. Anyone who tels you otherwise is full of it.
The specific usecases, for which MVVM has been designed, are situation, when you are unable to modify either the model layer or view instances, or both.
P.S. Though, if you are using ViewModel instances as per ASP.NET MVC documentation, then you actually are NOT using MVVM. It is just Model2 MVC with different names for things (where "viewmodels" are actually views and "views" are templates). They kinda messed up when they marketed Rails-like architecture as "MVC".
I've always viewed Models as the "Building Blocks" of the application. They are usually self-contained classes with some properties and perhaps some rudimentary validation or logic for its own properties only.
View Models on the other hand are my actual application classes that end up using the "building blocks" (Models) when building and running the application. They do things like perform advanced validation, process commands, handle events, any kind of business logic, etc.
It should be noted that you don't have to expose your Model's properties in your ViewModel like you have in your example code. Doing so is the "MVVM purist" approach as it completely separates your Model layer from the View layer, however it's also perfectly acceptable to expose the entire Model to the View instead. This is what I typically use in most small projects due to it's simplicity and lack of code-duplication.
public MyModel CurrentModel
{
get { return _model; }
set
{
if (_model != value)
{
_model = value;
RaisePropertyChanged("CurrentModel");
}
}
}
However if there are cases where only a few properties from the Model is needed in the View, or if the project is large enough where I'll want to keep the layers totally separate, then I expose my Model's properties to the View through the ViewModel like you have in your example code.