Drive an Aggreagte View Model by setting properties or calling methods? - c#

I'm debating with myself about the best practice approach to controlling an Aggreate View Model class that I've created for my app... Let's say I have an aggregate model that has a PurchaseOrder object and a list of line items that belong to that Purchase Order, and a few other auxuliary/related objects. This view model is just a wrapper around all these objects that you would typcially need when working on any give PurchaseOrder.
After after creating an instance of this view model, I then want it to load up a PurchaseOrder (and it will load the PurchaseOrderLineItems automatically and saturate all the other related objects)...
So, to instruct the view model to load up a PurchaseOrder, is it more acceptable to:
Instruct the view model by setting a property on it (and let the property setter of the view model class respond by loading up the data)
ViewModel.PoNo = 1234;
or
Call a method on the view model to do the work:
ViewModel.LoadPurchaseOrder(1234);
Just to give a few mode detials about the Aggregate View Model, it basically looks like this:
public class ViewModel
{
//-- private fields
PurchaseOrder _Po = new PurcaseOrder();
List<PurchaseOrderItem> _PoLineItems;
Vendor _Vend = new Vendor();
int _PoNo;
//-- public properties here
ViewModel(){} // Constructor
}

Does this ViewModel serve any purpose other than relating all the PurchaseOrder informaton together? If not i would say you should pass your purchase order in the constructor of ViewModel because it seems like ViewModel would only be in a valid state if it had a PurchaseOrder.
EDIT: Given the 2 options you have listed, I think a method call makes more sense than setting a property as it is easier to tell that you are loading a PurchaseOrder into this ViewModel. As a developer, I wouldn't think that setting an integer property would end up loading all kinds of objects on the ViewModel, but one might expect that from calling a method.

Related

MVVM Read data from database to Model or to ViewModel?

I'm currently learning about WPF and MVVM so I've decided to create a sample application.
To my knowledge a Model is for the back end. E.g. if you have "Spaghetti" as a Model, it would have properties like "Name", "colour", "length" etc. It follows a 1:1 relationship
View Model is for the front end so the View will use what you add to the View Model. e.g. displaying a list of the different names of Spaghetti.
I'm trying to read data from the database and display all the spaghetti names to the View. I've managed to do it but I feel like I'm missing the objective of MVVM as the way I have done it does not require the Model.
Here is the code:
MainWindow.xaml.cs
public partial class MainWindow : Window
{
MainWindowSpaghettiViewModel vm = new MainWindowSpaghettiViewModel();
Service businessLogic = new Service();
public MainWindow()
{
InitializeComponent();
vm.SpaghettiNameCollection = businessLogic.GetSpaghettiNames();
DataContext = vm;
}
}
Model: Spaghetti.cs
public class Spaghetti
{
public string Name { get; set; }
public double Length { get; set; }
public string Colour { get; set; }
public decimal Price { get; set; }
}
View Model: MainWindowSpaghettiViewModel.cs
public class MainWindowSpaghettiViewModel
{
public List<string> SpaghettiNameCollection { get; set; }
}
BusinessLogic Layer: Service.cs
public class Service : IService
{
DBHelper db = new DBHelper();
public List<string> GetSpaghettiNames()
{
return db.GetSpaghettiNames();
}
}
DataAccess Layer : DBHelper.cs returns a list of spaghetti names by using a select statement.
Am I approaching this correctly as I've seen examples before where others have populated the View Model properties directly from the database?
How would the application flow? For example, in this window, I would like the user to select the name of the spaghetti they would like more information for, from the list I have just created.
After they select a spaghetti, they go to the next window where they can see all the information about the spaghetti (like the properties in the Model). Do I just create a new ViewModel with the same properties and do what I did above or do I populate the Model and then populate the ViewModel from that?
Looks good so far but you could use List<Spaghetti> instead of List<string>
and directly read the items into this List in the ViewModel from the database. So the Model is actually the template.
Do I understand you correctly? Your question is why do you need the Model class while you load the data directly into a ViewModel class?
The Model actually holds the data and provides the data for the ViewModel.
The ViewModel is the logic for the View.
If you need more data for the view than the Model can provide but the Model also should not have and provide you create a ViewModel for data Model exclusive for the View but populate it with the Data from the Model which gets populated from for example an SQL Database. Otherwise, it's the same. If you only need a small portion from an entire Model for the View you create a ViewModel which has only the Properties needed for that purpose.
An example would be you have a TreeView and you need a Property named "IsExpanded" to have control about that. This Property has nothing to do with the pure Data and therefore should not be in a Model class itself. A non purist would say okay, but you could write a partial class for that model and ignore some View needed properties via attributes for the database.
If you only show a Name of that Model to the user, it would be enough to have a List of type string.
So there is no direct answer. You may expose your Data directly via ViewModel or via another ViewModel for the Model class with less or more properties, fields etc.
After they select a spaghetti, they go to the next window where they
can see all the information about the spaghetti (like the properties
in the Model). Do I just create a new ViewModel with the same
properties and do what I did above or do I populate the Model and then
populate the ViewModel from that?
It looks like you need the same properties stored in the database for the View itself.
You could load all items directly and populate a List of Spaghettis with it or just populate strings but load the required data for the item if requested on the next page or wherever.
In general if you got loads of data many would say:
You shouldn't load all the data from the Database, load only what you need.
It think it just depends on the data. Some MVVM purist would always say, create a ViewModel for the Model and load and expose only the Data needed at that time.
I suggest you to read this, I hope it helps. If you have further questions ask.
https://www.wintellect.com/model-view-viewmodel-mvvm-explained/

How should I be binding my business models to my views?

I've come across an interesting question during my development. Right now, I use a database-agnostic unit of work layer to abstract the access of data from the actual database dependencies in my ASP MVC 4 web application.
Each individual database project which implements the unit of work interfaces are aware of my business models (models that go directly to/from the database). I'm not too sure how I feel about this approach, but that's not the question I am going to ask.
Should I be using a solution like AutoMapper to convert my business models to/from domain models - models that are passed to the view and used for any work that shouldn't have access to database fields (i.e., IDs)?
For example, consider inside my BusinessModels project, I have the following classes
BusinessModels
/UserAccounts/
User.cs
- ID
- Username
- HashedPassword
- Salt
UserSettings.cs
- IsSubscribedToNewsletter
- AllowDirectEmails
Would it make any sense to bind these User, and UserSettings models into a single model using AutoMapper like so
MyProject
/DomainModels/
User.cs
- Username
- HashedPassword
- Salt
- IsSubscribedToNewsletter
- AllowDirectEmails
for the purpose of views?
This question also extends to non-MVC projects but I feel seeing as I am working on an MVC project it would make more sense to ask it in that tag.
TLDR is there any point in mapping business models/entities to view models or does that provide an unnecessary layer of abstraction? And if so, would the Repositories contain business models, or view models (which map automatically to business models under-the-hood)?
You can use view models for two different things:
rendering a new view (GET action), passing the view model object as the model for the view
receiving data back from the view, in a Post Action (POST action), using the view model as parameter
(I know, the second is arguable. But it's not strange to use the view models for this)
The model for the GET action needs all the properties neccessary to render the View:
the values of the entity you're showing/editing
extra values needed to render the view (for example SelectLists for drop down lists)
Suppose that you have a User which can belong to one UserGroup.
In this case, if you want to edit the user, the model needs:
the User data
a list of UserGroups
I'd use a model like this:
public class EditUserModel
{
public User User {get;set;}
public SelectList UserGroups {get;set;}
}
As you can see, I directly add the User as a property. But I don't add the list of categories as a property, because I don't need the whole list of categories, with all their properties in the view. Besides, if you unit test the controller you can verify that the SelectList is as expected (that couldn't be done if you created the User Groups list in the view)
But, what if you don't need all the properties of the user in the View? Is it worth removing the User property, and add individual properties for Name, Email, JoinedData, Active... ? I think the anser is NO. Imagine you add/remove or rename some of the User entity properties. If you had individual properties in the view model, you'd have to change them as well, before updating the View. And, if you rely on automatic mapping (auto mapper, value injecter) you would't even realized if you make some mistake.
I also said that the view model can be used for posting back data to the controller. So you could do this:
[HttpPost]
public ActionResult Edit(EditUserModel userModel)
If you do so, the model binder will populate the userModel with the values in the form controls. So you'lll get back a half empty model. In this case, the UserGroups list would be null, and, depending on how many of the User's properties you edit, the User could also have many null/non-initialized properties.
To avoid making errors, in some occasions is advisable to create a different model (and probably auxiliary classes) to make it clear what is expected to be posted to the model.
For example, if you have an action to show the whole user data, but which only allows to change its password, you could create a class with two properties: Password, and PasswordConfirmation.
In this case, the view model for the POST could only have the Password and PasswordConfirmation. And derive a model for the GET which has this inherited properties, and also the list of User Groups and the User.
Why inheriting and not using independent classes? Simply beacuse when you use something like Html.TextBoxFor(m => m.User.Name), the Model Binder will be able to set the Name property of the User property, only if the parameter for the post action has the same structure. I.e. if the view model for the get has this structure:
public ChangePasswordModel
{
public string Password {get;set;}
public string PasswordConfirmation {get;set;}
// extra properties, like the list of user groups, the user data...
}
And the model for the post has this structure:
public PostedChanegPasswordModel
{
public User User {get;set;}
}
The content of the input rendered by Html.TextBoxFor(m => m.EditedUser.Name) won't be bound to the User.Name of the PostedEditViewModel.
But if you make this:
public EditUserModel : PostedEditUserModel
{
// extra properties, like the list of user groups
}
the data will be bound without any problem.
In general you have to be careful with the models you use for posting and getting. And I recommend using as many different view models as neccesary.
When to use automatic property mapping to completely new view and different models?
You must have a very strong reason to have different view models. This could be a result of starting the application from outside in (i.e. design first) or because a team is developing the UI before or while the business logie is being implemented.
In this case you can find that the classes for the view models, and the views themselves are already defined, and are quite similart to your entities, but not exactly equal. This is one case when I think it can be good to use mappers.
The other reason to use different classes would be to decouple the interface from the logic. But this usually only happens in the previous case.
Regards viewmodels I treat them like a summary of the data you wish to work with.
So taking from your example, your viewmodel would contain data from both the User and UserSettings classes. Let's say you had a view named UserData.cshtml then I would code it up like so:
public class UserDataViewModel
{
public string Username { get; set; }
public bool AllowDirectEmails { get; set; }
// etc ...
}
public ActionResult UserData()
{
var viewModel = new UserDataViewModel();
viewModel.UserName = "Whatever";
viewModel.AllowDirectEmails = false;
// Or however you get the data for the user.....
return View(viewModel)
}
Hopefully you get the idea. So you are on the right track with merging information from externals classes into one viewmodel class. Bascially tie everything together in the viewmodel class.
I name the viewmodel class the same as the view that it's going to be used for. This can help documentation, as well as make it easier for devs new to the code to follow.

WPF - MVVM Viewmodel setup

I'm having some issues with the setup i'm currently using with my mvvm application. Having seen some posts on here, i get the feeling i may be doing this slightly wrong.
I have several models which contain lists of child models such as:
Project - Contains a list of proformas
Proforma - Contains a list of shipments orderedItems
Shipment - Contains a list of Containers
Container - Contains a list of packages
We do not have any viewmodels that relate directly to these model currently, we instead simply have viewmodels that represent the list of models, for example we have a proformalistviewmodel which simply contains a list of proformas.
My issue is, that with this setup i'm a little confused as to what viewmodel should own which data, for example the ProfomalistViewModel has a reference to the currently selected Project, all the data management for these models (the loading and saving of the list of proformas) is done via manager classes which are loaded via DI.
My question is should i instead be following what I'm seeing and having a ProjectViewModel which contains a list of proformas, and a ProformaViewModel which contains a list of shipments and ordereditems and so on.
The reason for this, is that originally none of the models we're linked, projects did not own a list of proformas they were instead loaded separately via the managers using the selected project ID (using a relational db) and we're currently changing the models to the system i described above.
A viewmodel should be a model of the user interaction for a particular area of functionality
For instance, if you have a project list page and the user can do certain things like delete a project, edit a project, print information about the project then you should design a viewmodel that contains the data and actions associated with this interface:
e.g. the viewmodel should contain:
* A bindable container for the project data (list of projects)
* Actions that handle edit/delete interaction
* An action to handle the print functionality
The actual functionality inside these actions may not be contained within the viewmodel (the VM may have received injected services such as the print service or the project repository) but the responsibility of execution of these actions lies with the VM.
It may also be necessary to wrap each data item (project) in a viewmodel so that additional interaction dependent properties/actions can be added - such as the 'selected' property (imagine the user wants to multi-select a load of projects in the view - you could add a selected property to the ProjectViewModel which will wrap each project which makes binding easy)
You may end up with something like the following:
public class ProjectOverviewViewModel
{
public IList<ProjectViewModel> Projects { get;set; }
public ProjectViewModel SelectedProject { get;set;}
public void EditSelected()
{
// Code to open edit page for the selected project
}
public void Print()
{
}
}
and the ProjectViewModel with a selectable property
public class ProjectViewModel
{
// Either put the actual data item in here and wrap it:
public Project Project {get;set;}
// Or copy properties onto the viewmodel using automapper or some other mapping framework...
// or manually :(
// e.g. properties mirrored from the entity object:
public int ProjectId { get;set;}
public string ProjectName { get;set;}
// The selected property - now your 'Selected' logic is a function of the view/viewmodel
// not the entity. The entity should only be concerned with data persistence
public bool IsSelected {get;set;}
}
You may also want to composite viewmodels together in order to build more complex views. Imagine you have a projects page and a "users involved in a project" page, and you wanted another page that showed both side by side (and allowed you to click a project which would refresh the users pane) - this is possible by compositing the viewmodels (by creating another viewmodel which contains the two viewmodels as properties and wires up the interaction between the two)
public class ProjectAndUserOverView
{
public ProjectOverviewViewModel ProjectOverview {get;set;}
public ProjectUsersViewModel ProjectUsers {get;set;}
// Code here to listen for property changes in ProjectOverview and if SelectedProject changes
// call ProjectUsersViewModel to refresh the data for the selected user
}
Ultimately you are just modelling the user interaction, and the more modular you can make it, the easier it will be to make cleaner more maintainable code
There are some good MVVM frameworks - my personal fave is Caliburn Micro as it makes the above very easy (it heavily uses conventions by default) and is easy to get into.
MVVM is design pattern which have 3 parts: Model, ViewModel, View. DIagram looks like this:
http://en.wikipedia.org/wiki/Model_View_ViewModel#Pattern_description
You use ViewModels wrong. Only data for displaying should be in ViewModel.
Your Model for example:
public class Project
{
public Proforma Pr{get;set;}
}
public class Proforma
{
public string Name{get; set;};
}
You have View for project display(I inject ViewModel to constructor, tou can use DataContext instead):
public partial class ProjectView
{
private ProjectViewModel vm;
public ProjectView(ProjectViewModel vm)
{
this.vm = vm;
}
}
If you want to display proforma name on Project view, you should provide it as string in ViewModel.
public class ProjectViewModel
{
private Project pr;
public string ProformaName{get{return pr.Pr.Name;}}
}
If you provide Proforma like proforma, your View will know about model. It will be a violation of the pattern.
My five cent is that MVVM is a pattern, not a religion. I use it at far as it goes and makes sense. There's many parts where MVVM is undefined (like user interaction from commands), and I read a lot about ViewModels being created just to fit MVVM (which bloats both design and object count). I would suggest you think more DataContext-wise, like "Selections of global interest are kept in a global DataContext, Proforma related data is kept in a Proforma DataContext" and so forth, where DataContext is some sort of ViewModel. In the end, you'll probably wind up rigging those up with UI.
You shouldn't create ViewModels for your model objects.
Generally speaking, a ViewModel should belong to a UserControl. Its role is to wire your view (your XAML) together with your model (business logic).
In your case, if I understand it correctly, you have a bunch of classes that implement business logic (Project, Shipment etc.). Your ViewModel will have access to the business logic, and provide properties for your view to bind to.
I do not see any problem with having view models that wrap model data objects. Viewmodels do not have to be "one per view". They can represent a row in a list or whatever.
Having said that, I am quite happy binding directly to model objects and I do it a lot. The only time I create a view model to wrap it is if I need extra state per object that is required by the view.

Does my View Model have my Model and my Repository instance?

Hopefully I am being clear here. I have a ViewModel called A. I have a Model called M. I have a Repository for Model M and the DB stuff it maps to called RM.
Would my ViewModel, A, have a Property of my Model M AND my one for my Repository RM.
I would then use it by calling the various methods on RM and bind to M which I would pass to certain methods in RM like Save().
Make sense? Is that "normal" or even close?
You could be describing a typical situation, depending on your preferences. If your view model wishes to work with entities, then it could do so via a repository which you could inject as a dependency using constructor injection, and your view model could work against an abstraction rather than a specific implementation of your repository.
If you wished to access the repository at a later point after construction, then you could assign the repository to a private field or property for example.
In terms of your model, you could have a property which exposes this to the view so that you didn't need to duplicate the properties of the model on your view model. However, this would depend on whether you are happy with the view having direct access to your model which could be a violation of the LoD (Law of Demeter) in order not to violate the DRY (Don't Repeat Yourself) principle.
One approach would be to expose a property of type M, like you have at the moment, from the view model. The view will then bind to the properties of this exposed model. On your view model expose a method called Save and your view will call this method on the click of a button (binding can be used if you're using WPF). The Save method will then create an instance of the repository, add the property of type M to it and then save the repository.
Example:
public class ViewModel
{
public void Save()
{
// Create your repository
// Add this.Model to the repository
// Save the repository changes
}
public M Model { get; set; } // Bind your view to this.
}
This allows you to perform other operations before and after the save, you can use other properties to decide if, and what you save, and how your view model "saves" remains part of the view model and not the repository.
I would also recommend looking into using dependency injection, as mentioned by #devdigital, for your repository. This would mean you wouldn't have to create your repository in your Save method and instead you would use the instance of the repository passed into the constructor of the view model.

How do i access data from multiple models/controllers in my view?

I'm trying to create a view that will create a subcategory.
In order to create this view I inherit my model for subcategories in the view in order to access the required attributes etc.
Now one of the attributes I wish to set on my subcategory object is a reference to a normal Category.
However I am not sure how to populate my dropdownlist with category items since I am already using the model of subcategories.
My question is, what would be the best way to access a SelectList of category objects in my subcategory view.
I've considered using partial views or perhaps transfering the data in my ViewBag or ViewData.
What would be the best way to do this?
You need to use a ViewModel. This is basically a class that you use to bring together all the pieces of the various models required for your view.
It might look something like:
public class CategoryListingsVieWModel
{
public IList<ISubCategory> Subcategories{get;set;}
public IList<ICategory> Categories{get;set;}
[...] // Any other data your view needs
}
This then becomes the model for your view which your pass from your controller.

Categories

Resources