I'm using the MVVM pattern in our WPF application to allow for comprehensive unit testing. The MVVM pattern itself is working great, however I'm struggling to adapt the pattern in a way that means I can use the design-time data support of WPF.
As I'm using Prism the ViewModel instances are generally injected into the constructor of the view, like so
public MyView(MyViewModel viewModel)
{
DataContext = viewModel;
}
Dependencies for the ViewModel are then injected into the constructor, like so
public class MyViewModel
{
public MyViewModel(IFoo foo, IBar bar)
{
// ...
}
// Gets and sets the model represented in the view
public MyModel { get; set; }
// Read-only properties that the view data binds to
public ICollectionView Rows { get; }
public string Title { get; }
// Read-write properties are databound to the UI and are used to control logic
public string Filter { get; set; }
}
This is generally working really well except when it comes to design data - I wanted to avoid compiling design-data specific classes into my released assembly and so I opted to use the {d:DesignData} approach instead of the {d:DesignInstance} approach, however in order for this to work correctly my ViewModel now needs to have a parameterless constructor. In addition, I also often need to change additional properties either to have setters or to be modifiable collections in order to be able to set these properties in XAML.
public class MyViewModel
{
public MyViewModel()
{
}
public MyViewModel(IFoo foo, IBar bar)
{
// ...
}
// Gets and sets the model represented in the view
public MyModel { get; set; }
// My read-only properties are no longer read-only
public ObservableCollection<Something> Rows { get; }
public string Title { get; set; }
public string Filter { get; set; }
}
This is worrying me:
I have a parameterless constructor that is never intended to be called and isn't unit tested
There are setters for properties that only the ViewModel itself should be calling
My ViewModel is now a jumbled mixture of properties that should be modified by the view, and those that shouldn't - this makes it tricky to tell at a glance which piece of code is responsible for maintaining any given property
Setting certain properties at design time (e.g. to see styling on the Filter text) can actually end up invoking ViewModel logic! (so my ViewModel also needs to be tollerant of otherwise mandatory dependencies being missing at design time)
Is there a better way to get design-time data in a WPF MVVM application in a way that doesn't compromise my ViewModel in this way?
Alternatively should I be building my ViewModel differently so that it has more simple properties with the logic separated out somewhere else.
First, I would recommend you to have a look at this video where Brian Lagunas provides several best practices about MVVM. Brian is - at least - involved in the development of Prism, as his name appears in the nuget packages information. Didn't check further.
On my side I only use bits of Prism, and my Model and ViewModel always offer blank constructors (like what Brian shows), the data context is assigned in the view's XAML, and I set the properties values like :
<MyView.DataContext>
<MyViewModel />
</MyView.DataContext>
and
public void BringSomethingNew()
{
var myView = new View();
(myView.DataContext as ViewModel).Model = myModel;
UseMyView();
}
Another benefit with this approach is that the ViewModel is created once, with the same path at design and run time, so you create less objects and save GC efforts. I find this elegant.
With regards to the setters, the design data will still work if you make them private, like:
public string MyProp { get; private set; }
Ok, customize it to manage NotifyPropertyChange at your convenience, but you've got the idea.
Now, I don't have yet a solution to manage ObesrvableCollections (I face the same problem, although putting multiple values in XAML sometimes work... ???), and yes, I agree that you have to manage the case when the properties are not set, like setting default values in the constructor.
I hope this helps.
I too have worked with NUnit testing with WPF and MVVM implementation. However, my version is reversed from yours. You are creating the view first, then creating the model to control it.
In my version, I create the MVVM model FIRST and can unit test it till the cows come home and not worry about any visual design... if the model is broken, so too will the visual implementation.
in my MVVM model, I have a method to "GetTheViewWindow". So, when I derive from my MVVM baseline, each view model has its own view its responsible for. So via a virtual method, each instance will do its own new view window when being applied for production.
public class MyMVVMBase
{
private MyViewBaseline currentView;
public MyMVVMBase()
{ // no parameters required }
public virtual void GetTheViewWindow()
{ throw new exception( "You need to define the window to get"; ) }
}
public class MyXYZInstanceModel : MyMVVMBase
{
public override void GetTheViewWindow()
{
currentView = new YourActualViewWindow();
}
}
Hope this helps as an alternative to what you are running into.
Related
I'm still not totally sure what constitutes a view model. I have a class that I use to wrap my model and alter the data slightly, but I am not sure whether it constitutes a view model. What is necessary to be considered a view model? Is it merely not supposed to have direct dependencies on the view, so that the viewmodel does not know how the view uses its properties and the view does not know what is in the viewmodel? and when the view wants to update anything it just gives some abstract command that the viewmodel takes and uses to update the model?
As I understand it in MVVM, I'm supposed to use properties on the view that bind to properties on the viewmodel that bind to properties on the model.
and in the reverse direction, I'm supposed to use commands from the view to the viewmodel, which then can either uses Icommand to command the model, or can just call public functions in the model to make changes to it.
One confusing thing is that in the example of MVVM that I saw made it seem like in MVVM the view should have no code behind other than perhaps creating commands, but I don't see how I could do that in my current project. I'm making a custom control using lots of controls that are interacting on events.
how would I make one treeview expand on another treeview's expand without using events?
Often, View Models end up being very similar to your domain models. One of the main goals of having View Models is to separate the GUI development from the business logic. For example, let's say you have a "User" domain model that has an IsAdmin property which you don't want exposed to the View. You create a View Model called "UserViewModel" that still has the ID, Username, and Password (see example code below), but doesn't have an IsAdmin property. Another approach is to use the domain model inside your view model, see the "AlternateUserViewModel" class below. There are pros and cons to any View Model solution. Creating the UserViewModel class with properties means you are essentially duplicating the objects you created for the domain model, since often times your domain models will be very similar to your view models. With the AlternateUserViewModel approach, there's not clear separation between your business logic layer and your GUI layer because the view model still needs to "know" about the domain model. What approach you decide on really depends on the environment you're working in. For personal projects, I like using the 2nd approach because separating the business logic from the design layer isn't such a major concern that I wouldn't want to let the view model layer "see" the domain model layer, but for a large corporation where you have separate teams working on the design layer and the back-end, the first approach may be preferred.
public class User
{
public int ID { get; set; }
public string Username { get; set; }
public string Password { get; set; }
public bool IsAdmin { get; set; }
}
public class UserViewModel
{
public int ID { get; set; }
public string Username { get; set; }
public string Password { get; set; }
}
public class AlternateUserViewModel
{
public User User { get; set; }
public User ToDomainModel()
{
if (User == null)
return null;
// if this is an existing user, retrieve it from the database so you're not overwriting the IsAdmin property
if (User.ID != default(int))
{
User existingUser = UserService.GetUserByID(User.ID);
existingUser.Username = User.Username;
existingUser.Password = User.Password;
// IsAdmin is not set because you don't want that property exposed in the View Model
return existingUser;
}
else
{
return new User
{
Username = User.Username,
Password = User.Password,
IsAdmin = false
};
}
}
}
You have a number of questions here (consider breaking it into multiple posts). I'll try to answer some.
I think of ViewModel as THE app, in other words, this is where most of the app's logic happens.
In other words, ViewModel receives an input of:
Commands from the View
Changes in bound properties from the View
Events from a background service (e.g. when data is received from the Web)
Other events from the system or from domain models
and generates an output of:
changing properties that the View would bind to (e.g. IsBusy that could cause the View to display the waiting indicator)
showing/hiding stuff in the View (indirectly, of course, for example using various bool Properties)
causing navigation to other Views (also indirectly, since it doesn't have direct access to NavigatonService available to the View).
Another way to think about the ViewModel is like so: the ViewModel is the complete user-facing state of the system. In other words, this state and nothing else would be used by the View to show/present this state in some user-understandable way.
About Commands vs. Events:
Unfortunately, not everything in WPF is exposed as a Command. Buttons generate Commands, but not all controls do.
Luckily, you can use Behaviors to translate Events to Commands and some frameworks provide the implementation. Here's an example of how MVVM Light does this. Blend also provides this functionality.
Also, why do you need to generate Commands in the code-behind? Frameworks like MVVMLight provide an implementation of a RelayCommand (or DelegateCommand) that removes the need to create different ICommand implementations. You can just as easily implement it yourself.
My WPF application follows the MVVM pattern. There are three views:
MainWindow
LoginView
ProjectsView
LoginView and ProjectsView are user controls imported by the MainWindow. Both views have their view model assigned. LoginViewModel defines a property ProjectList which is set by calling a webservice. Now LoginViewModel needs access to the ProjectList property and others.
I am aware that one solution might be a redesign so that there is only one view and one view model. I would do that as a backup solution but I would favor not to do so.
How should this be done? Should I use some kind of EventAggregator like in Prism? Or are there other ways to do this?
So if i understood clearly, ProjectList property should be accessed from both 'LoginViewModel' and 'ProjectsViewModel'. I'd try to implement it in the 'MainViewModel' so child viewmodels can access it in a natural way.
An IEventAggregator is like a box in which you can add events, or find and subscribe to one, so i would say it's not what you need.
Anyway, you could register your custom interface (box type) in the UnitySingleton.Container, which would expose ProjectList for it to be accessible everywhere. This approach makes a lot of sense when modules, which are separate assemblies, need to communicate whith each other.
If this is overkill or not in your case is something you should decide, i'd personally go with the 'put it in the mainviewmodel' option.
-- Sample -- (not tested)
public class MainViewModel : ViewModelBase
{
public MainViewModel()
{
LoginVM = new LoginViewModel(this);
ProjectsVM = new ProjectsViewModel(this);
RetrieveProjectList();
}
public LoginViewModel LoginVM { get; private set; }
public ProjectsViewModel ProjectsVM { get; private set; }
public object ProjectList { get; private set; }
private void RetrieveProjectList()
{
ProjectList = ....
}
}
It's pretty simple as you see, LoginVM and ProjectsVM will hold a reference to the MainViewModel that created them, therefore giving them access to ProjectList.
How should this be done? Should I use some kind of EventAggregator
like in Prism? Or are there other ways to do this?
Here are a few ideas:
You can create a view-model class that both view-models
inherit from. This base class will contain the shared properties.
Create a static class that contains the shared properties.
Using dependency injection, create a class that contains the
properties, register it as a singleton in your container and inject
it into your view-model's ctors.
Also, I believe that the EventAggregator is best suited for communicating between modules/assemblies. In your example, it seems like everything is in the same assembly.
I have recently started learning wpf and am trying to use mvvm.
My understanding is that in the mvvm neither the view or the model should know the other exists.
What I am trying to do is show a list of customers on the screen. But if I code the viewModel as shown below. which is similar to many examples I see on the net, then I end up with some code looking like this
class Customer
{
public String Name {get;set;}
public String Address {get;set;} }
}
class MainWindowViewModel
{
ObservableCollection<Customer> customers = new ObservableCollection<Customer>();
public ObservableCollection<Customer> Customer
{
get {return customers;}
}
public MainWindowViewModel()
{
//cust1 and cust2 are Customer objets
customers.Add(cust1);
customers.Add(cust2);
}
}
Now if I create an instance of my MainWindowViewModel and set it as the datacontext of my MainWindowView (my view) and i further bind the viewmodels Customers property to a listBox, then the view will need a reference to the assembly that contains my Models.
So my questions are.
1) Is adding a reference to Models assembly allowable in MVVM, since this would mean the view knows about the model.
2) would a better solution be to wrap each Customer object in a CustomerViewModel and have the MainWindowViewModel contain ObservableCollection of CustomerViewModel
instead of ObservableCollection of Customer. This would separate the models completely from the view.
I'm not sure why you think the project containing your views requires a reference to your model project? There is nothing in your view which references your models directly - your binding expressions in XAML are linked by name only, and to properties on your view model anyway, not your model.
Wrapping your model in a view model is a good option if your view requires additional data than your model provides, and it is undesirable to change your model. For example, you view may need to display the Age of a User type, but User only has a DateOfBirth property. Creating a UserViewModel with an Age property would be a good option if you didn't want to alter your model.
Answers to your questions:
What is bad about the View referring the Model? This is absolutely ok when it simplifies the code. Just the other way around (Model -> View) is bad practice.
You don't need to wrap each Customer object in a CustomerViewModel when you don't have special needs. I would suggest to follow a pragmatic way and keep the code simple.
You might be interested in the BookLibrary sample application of the WPF Application Framework (WAF) which shows the scenario you describe here.
We usually create a CustomerViewModel. That is enforced by our generic CollectionViewModelBase class. This unsures that every part the user interface uses is exspecially created to be displayed and we don't have any UI related code in the models which are often serializable POCOs.
The MVVM pattern is similar to any other MVx pattern (MVC, MVP, ...) in that it encourages separation of concerns (SoC), which in turn improve maintainability / testability of your code. Beyond the usual SoC, MVVM gives the following:
Unit testing of your view logic; this is because you move logic from your view into your view-model, making your view as dumb as possible.
Developer-designer workflow; because the view is 'dumb', it is easier to work with the XAML without the logic behind it.
Regarding visibility, i.e. what is visible to what, it is strictly as follows:
Model <= ViewModel <= View
In other words, the ViewModel can see the Model, but the Model cannot see the ViewModel. Likewise, the View can see the ViewModel, but not vice-versa.
Because the ViewModel has no reference to the View, it enables your code to be executed without any view components present, this enables (1) above.
The purpose of your ViewModel is to 'shape' your Model to make binding to the View easier. If your View is simple, then it is quite acceptable to do the following:
Model <= View
This still allows (1) unit testing, (2) developer-designer workflow.
It is also fine to use a hybrid approach, sometimes exposing your Model to your view, other times wrapping it in a ViewModel. For example:
http://www.scottlogic.co.uk/blog/colin/2009/08/the-mini-viewmodel-pattern/
Please don't create a bunch of boiler-plate ViewModel code, just because you think you have to!
You will definitively want to wrap your models in view only objects like below :
/// <summary>
/// Business model object : Should be in your separate business model only library
/// </summary>
public class BusinessModelObject
{
public string Prop1 { get; set; }
public int Prop2 { get; set; }
}
/// <summary>
/// Base notifying object : Should be in your GUI library
/// </summary>
public abstract class NotifyingObject<T> : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public void NotifyPropertyChanged(PropertyChangedEventArgs e)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null) handler(this, e);
}
private static readonly PropertyChangedEventArgs ModelPropertyChanged = new PropertyChangedEventArgs("Model");
private T _model;
public T Model
{
get { return _model; }
set
{
_model = value;
NotifyPropertyChanged(ModelPropertyChanged);
}
}
}
/// <summary>
/// Model decorator : Should be in your GUI library
/// </summary>
public class BusinessModelObjectAdapter : NotifyingObject<BusinessModelObject>
{
public BusinessModelObjectAdapter(BusinessModelObject model)
{
this.Model = Model;
}
private static readonly PropertyChangedEventArgs Prop1PropertyChanged = new PropertyChangedEventArgs("Prop1");
private string _prop1;
public string Prop1
{
get { return Model.Prop1; }
set
{
Model.Prop1 = value;
NotifyPropertyChanged(Prop1PropertyChanged);
}
}
private static readonly PropertyChangedEventArgs Prop2PropertyChanged = new PropertyChangedEventArgs("Prop2");
private int _prop2;
public int Prop2
{
get { return Model.Prop2; }
set
{
Model.Prop2 = value;
NotifyPropertyChanged(Prop1PropertyChanged);
}
}
//and here you can add whatever property aimed a presenting your model without altering it at any time
}
I'm currently working on what will be my first real foray into using MVVM and have been reading various articles on how best to implement it.
My current thoughts are to use my data models effectively as data transfer objects, make them serializable and have them exist on both the client and server sides.
It seems like a logical step given that both object types are really just collections of property getters and setters and another layer in between seems like complete overkill.
Obviously there would be issues with INotifyPropertyChanged not working correctly on the server side as there is no ViewModel to which to communicate, but as long as we are careful about constructing our proper domain model objects from data models in the service layer and not dealing the the data models on the server side I don't think it should be a big issue.
I haven't found too much info about this approach in my reading, so I would like to know if this is a pretty standard thing, is this just assumed to be the de facto way of doing MVVM in a multi-tier environment?
If I've got completely the wrong idea about things then thoughts on other approaches would be appreciated too.
You can use whatever model you feel comfortable with, yes all of your properties will need INotifyPropertyChanged behavior. How this will effect the service layer is entirely down to your implementation.
I'm assuming that you ment that you bind to your DTO's in your view?
How I see it is that there is an impedence mismatch between the layers of the application, that is your
Domain Model probably looks simliar to your Relational Model, with subtle but crucial differences. There is also
a mismatch between the Domain Model and your DTO's (objects may be flattened, computed properties, etc, ...). It's tempting to bind directly to the DTO's as they are probably designed to have what you need for the particular operation, however there is also an impedence mismatch between the DTO and what is needed by the view in order to acheive the desiged outcome. This is where the View Model comes in. The view model has responsibility to proxying the DTO properties to the view, it is responsible for letting the view know if there are validation errors, and routes commands to the appropriate handler (Save, Delete, etc, ...).
I tend to set things up in the following way :
// POCO object. Serializable.
public class AddressDto
{
public int Id { get; set; }
public string Street { get; set; }
public string City { get; set; }
public string Country { get; set; }
}
// IDataErrorInfo for validation.
public class AddressViewModel : INotifyPropertyChanged, IDataErrorInfo
{
private readonly AddressDto addressDto;
public AddressViewModel(AddressDto addressDto)
{
this.addressDto = addressDto;
}
public int Id { /* get and set for property changed event and update dto */ }
public string Street { /* get and set for property changed event and update dto */ }
public string City { /* get and set for property changed event and update dto */ }
public string Country { /* get and set for property changed event and update dto */ }
...
// IDataErrorInfo implementation
}
public class EditAddressViewModel : INotifyPropertyChanged
{
public AddressViewModel Address { /* get and set for property changed event */ }
public ICommand Save { /* setup command */ }
public ICommand Cancel { /* setup command */ }
private void Save()
{
}
private void Cancel()
{
}
}
Your EditAddressView would then bind to the EditAddressViewModel. Basically the rule is all of your UI behavior should be expressed in terms of your view model.
Yes that does mean extra work, howerver there are things you can do to simplify things a bit (code generation etc). I'm actually working on a library that aims to simplify whole MVVM process using a fluent api. Check it out at http://fluentviewmodel.codeplex.com/
I'm no expert on this. I had just the same scenario. I agree with you that that is quite an overkill. I've been using this solution for quite some time now and haven't encountered any issues. The INotifyPropertyChanged isn't a big problem for me since nothing on the server-side will subscribe to the PropertyChanged event. If you will use inheritance on your data models, then all must be serializable. In my scenario, I have two base classes for my data models: one that is used for data transfer, and the other not.
I decided to have a property "Model" on my ViewModel. In the model itself I already implement IPropertyNotifyChanged and IDataErrorInfo. In my ViewModel I thus skip properties where the code would simply "fall-through" to the model. Instead, the View binds directly to the model for those properties.
For more complicated cases, where I have to adjust the data in the model to fit the view, I do this in the ViewModel. Also, the commands, etc. are in the ViewModel. But I do not see the reason to have boilerplate code in the ViewModel repeating the same stuff which I already have in the model.
I need someone to confirm what I am seeing before I may a change to the domain of the application because of this issue. The issue is that when databinding against interfaces that inherit from one another, you can not see the properties on the base interfaces.
I am working on a WinForms application that uses databinding. This is in .net3.5 and no I can not use wpf.
Anyways, I have a setup something like this.
public interface IClassOne
{
string Prop1 { get; set; }
}
public interface IClassTwo : IClassOne
{
string Prop2 { get; set; }
}
public abstract class ClassOne : IClassOne
{
public string Prop1 { get; set; }
}
public class ClassTwo : ClassOne, IClassTwo
{
public string Prop2 { get; set; }
}
The base class would hold common properties and logic. The base interface would have those common properties on it so they would have to be implemented on each concrete implementation.
If I was databinding to my class structure above, I would be binding to IClassTwo. The problem is when I databind to IClassTwo, I can not see Prop1 in any of the designer operations for WinForms. Even if I get around that limitation and get a control to be bound to Prop1, it does not work.
However if I bind two ClassTwo, then databinding works.
I do not want to deal with the concrete classes because that would make using mocks and testing too hard. I also do not want to put everything on IClassTwo because I would have to repeat code when I make another concrete implementation.
What I need to know is if this truly doesn't work. If you know why, that would be a bonus.
Thank you
Tony
http://social.msdn.microsoft.com/Forums/en-US/winformsdatacontrols/thread/4151e6b6-44f7-45e2-9a8e-92c4f8539095/?prof=required
Here is a snippit of what is posted on MSDN as to why this doesn't work. The poster who wrote this goes by "franking".
No, it's not possible to bind to an interface! BindingSource offers some help to use a type as data source. Internally it will instantiate a BindingList<> instance using the type information. Also adding new items will work, but AddNew() will fail unless you subscribe the AddingNew event.