I am trying to implement MVVM in a new project (based on WPF & Prism) in which almost every screen (view) will have a search screen shown first where the user may choose to add/edit records.
The search screen takes a refernce to the VM which implements one of my interfaces ISearchProvider (which has one method IEnumerable Search(string criteria)).
Should this Search method return
a collection of VM's (with their models properly set) which will get shown in the grid in the search screen or
just Models so that when the user chooses to edit a record (Model), the chosen model is given to an instance of a VM which then gets edited or
some third option?
Whatever you plan to show to user should be wrapped with View Model.
You mentioned that user will select model to edit. This should be view model; user will select model (entity) to edit, but what he'll be shown (or what your view will see) should be list of view models representing some entity. User (or in this case view) should not need any knowledge of actual model.
Now, the view model should not be doing any search itself. It should delegate search to component that's responsibility is to perform search and return result (be it some kind of DAO, your custom tool - options may vary). What is more, the same view model should also be responsible for "feeding" view with data that may or may not arrive from search.
To give it code example:
public class UserListViewModel : ISearchProvider
{
private IUserFinder userFinder;
public UserListViewModel(IUserFinder userFinder)
{
this.userFinder = userFinder;
}
public ObservableCollection<UserViewModel> Users { get; private set; }
public void Search(string criteria)
{
var users = this.userFinder.Search(criteria);
// rebuild users collection - view will get notified of any changes
// made to .Users property as it is ObservableCollection
}
}
Also, it's probably good idea to make ISearchProvider interface expose single Search command. This way, binding from view is really simple.
To sum up, 2 simple points:
make sure your search logic is not in view model; let view model delegate the search
make search results be a part of view model or actual view model objects (so you can "feed" them to view easily)
My preference is to show ViewModels in the grid especially if you have a ViewModelBase class with a DisplayName that implements INPC and IDataErrorInfo. It's rare that my Model perfectly captures all the semantics of the presentation, and the VM is how we keep those concerns separate.
HTH,
Berryl
Related
I've been able to successfully return a model to a view and display the results in a strongly-typed fashion.
I have never seen an example where multiple models get returned. How do I go about that?
I suppose the controller would have something like this:
return View(lemondb.Messages.Where(p => p.user == tmp_username).ToList(), lemondb.Lemons.Where(p => p.acidity >= 2).ToList());
Does MVC let you return multiple models like that?
And then in the view I have this line at the top of the file:
#model IEnumerable<ElkDogTrader.Models.Message>
And I frequently make calls to "model" in the view.
#foreach (var item in Model)
If there were 2 models, how would I refer to them separately?
Is this possible with multiple models, or is this why people use ViewBag and ViewData?
You can create a custom model representing the data needed for your view.
public class UserView
{
public User User{get;set;}
public List<Messages> Messages{get;set;}
}
And then,
return View(new UserView(){ User = user, Messages = message});
In the view:
Model.User;
Model.Messages;
The ViewBag is useful because it is dynamically typed, so you can reference members in it directly without casting. You do, however, then lose static type checking at compile time.
ViewData can be useful if you have a one-off on your view data types and know the type and will be doing a cast in the view anyway. Some people like to keep the actual typed view pure in a sense that it represents the primary model only, others like to take advantage of the type checking at compile time and therefore make custom models needed for the view.
I believe ViewModel should be the way to go. Within the customary ViewModel, you can reference other models or define all the related domain models in the viewModel itself.
Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 6 years ago.
Improve this question
I have some kind of experience with WinForms coding but I am trying to do my new stuff with WPF (and the mvvm pattern).
One thing I am going round in circles for days searching the internet is to get the following right:
What do I have to implement in a model and what in the viewmodel when it goes down to "manage the repository (model?) data".
(I think) I do understand the basic concept of mvvm and decopeling all the data but I struggle to figure out the right implementation.
Let's assume I have an existing service (application without any UI) which is able to read values from a (ini) configuration file, do some stuff what its intended for, and write configurations to the local registry. Perhaps in future I want change the configuration to be stored in xml or json instead of ini. From my point of view this is all well placed in the existing code - let's say a configuration.cs file with a class configurations - which currently has absolutely nothing to do with my new wpf console application I want to implement next.
namespace ExistingConfigurationCode
{
public enum Setting
{
some,
values
}
public class ConfigurationItemProperties
{
public property1
public property 2
}
public class ApplicationConfiguration
{
List<ConfigurationItemProperties> config;
public void LoadConfig()
public void SaveConfig()
}
}
As just said, now I do want to implement a UI to enable a user to set up those configurations.
For what I have understand until now is:
the view is only the view and contains no logic at all
the viewmodel is responsible to "deliver" all needed informations to the view and receive commands from the view
the model is a model of the data we are dealing with
My problem in understanding (and knowledge how to proceed) is:
is this existing class already my model? But it does not make sense to add all the RaisePropertyChange stuff in this class because it is also used in the service. Also I have seen a lot of tutorials where I am told to not put any code in the model
if the existing class should be in my view model, what do I need the model for than?
Should the model have only a reference to my already existing class and control all read and write stuff to the registry/xml/ini through some kind of a wrapper?
Where do I have to add the "RaisePropertyChange" getter and setter? Because they are "controlling" the UI I would guess they should be placed in the view model, but I have seen a lot of examples where they are also in the model?
I got some kind of stuck here.
I thought the binding should be between the view and the view model, so the RaisePropertyChange should be in the view model, but in this case I would have to recreate everything a second time in the view model
Additional informations in response to comments
I understood now, that I can use my existing code as the model.
Besides the already existing "execution engine" which is utilizing the existing namespace/class, I have to create two applications with UI. An "admin console" and an end user console.
(I think) I am fine with the admin console, because it has a view for all the properties of ConfigurationItemProperties, so I can following Fabios first explanations.
But the second UI for the end user should have a stripped down UI, probably a listview with some checkboxes per list view item. And here is my problem.
For the listview I need the ObservableCollection, but for the items in the list view I need the "facade" fabio mentioned. Am I right so far?
If so, the ObservableCollection AND "ConfigurationItemPropertiesFacade" are working with the "model" which does not have any implementation of INotifyPropertyChanged or INotifyCollectionChanges stuff. But I think the "collections" must refer to the "single items" from the facade because the collection (from the view model) has no reference to the facade in the view model.
Try to think about MVVM like about three layers(not files) of your application.
View - namespace/project which contains only view logic(XAML and code
behind)
Model - namespace/project which contains all "business logic"
ViewModel - namespace/project which contains logic to link View and
Model without knowing about View's namespace. Another words ViewModel layer's responsibility to be a bridge between Model and View - Call Model's method, raise PropertyChanged event for when some value changed to inform View about changes.
So keep all your logic of configuration in the Model namespace.
In case when Model class need to be represent in the View with editing possibilities, create Facade class in the ViewModel layer
public class ConfigurationItemPropertiesFacade : INotifyPropertyChanged
{
private ConfigurationItemProperties _Model;
public string Property1
{
get { return _Model.Property1; }
set
{
if(Equals(_Model.Property1, value)) return;
_Model.Property1 = value;
RaisePropertyChanged();
}
}
public ConfigurationItemPropertiesFacade(ConfigurationItemProperties model)
{
_Model = model;
}
}
Use ConfigurationItemPropertiesFacade class as ViewModel in the View.
With this approach your Model layer stays clean and can be used anywhere.
In response on comment:
So tutorials telling it is not allowed to put "code" in the model are wrong, right?
Again try thinking about Model in MVVM not like a one class/file, but layer/namespace/project which can contains more then one class.
There is no right or wrong - you can implement your logic as you fill better suite your specifications. But if you will respect Single responsibility principle (https://softwareengineering.stackexchange.com/a/17170/102569), then you will separate responsibilities of ApplicationConfiguration to (I didn't know inner logic of methods Load and Save)
"Model" class which represents only data, class which has no
functionality just properties for keeping data.
You have this already ConfigurationItemProperties
"Service" classes which contains functionality of saving and loading
configurations. Your class can be spitted in two classes.
// Have one responsibility take configurations as parameter and save them somewhere
public class SaveService
{
public void Save(List<ConfigurationItemProperties> items) {}
}
// Have one responsibility load configurations and return them to the caller
public class LoadService
{
public List<ConfigurationItemProperties> Load() {}
}
So then your ViewModel will use those classes to represent and modify configurations in UI.
public class ViewModel
{
private readonly LoadService _LoadService;
private readonly SaveService _SaveService;
//Here you can use your"Facade" implementation
private ObservableCollection<ConfigurationItemPropertiesFacade> _Items
public ObservableCollection<ConfigurationItemPropertiesFacade> Items
{
get { return _Items; }
set
{
_Items = value;
RaisePropertyChanged(nameOf(Items));
}
}
public ICommand Save { get; set; }
public ICommand Load { get; set; }
public ViewModel(LoadService loadService, SaveService saveService)
{
_LoadService = loadService;
_SaveService = saveService;
// Create command instance for Save
// Create command instance for Load
var itemsList = _LoadService.Load();
var facadeItems = itemsList.Select(item => new ConfigurationItemPropertiesFacade(item));
Items = new ObservableCollection(facadeItems);
}
}
Let's think about these definitions:
Model - Data access and business Logic.
ViewModel - it's responsibility is to provide model's data and logic to view in such way that is easily consumable from view.
I believe that these definition gives you clear answer:
ExistingConfigurationCode class should be considered as part of your model.
Few more thoughts however:
INotifyPropertyChanged and INotifyCollection changed is not limited to DataBinding or WPF. These interfaces are much more general.
There nothing wrong about implementing INotifyPropertyChanged in a Model if you want your model to notify other layers or compoments about changes
It's common practice that you bind your Views directly to Model entities. ViewModel often just expose entity from Model as a property.
Wrapping model properties in ViewModel is one way of doing it. Another way is having separate properties in ViewModel with their own backing fields. You set the ViewModel properties to initial values when user visits the page and you save the edited values back to Model when user clicks save.
Just to make it clear, my question is how do you CREATE multiple objects using a single view. My ViewModel works fine, I can display multiple objects no problem.
Its been a while between .NET coding (last time I was coding in 2.0). I have created an MVC 4 project and successfully created a ViewModel (displaying data on a single view from multiple objects).
However, I cheated. I populated the database directly. I now face the question in reverse, what is the best practice for creating multiple objects from a single view?
In my example, I have a User, who has a userId. The userId is a foreign key in UserDetails.
Just trying to get back into the swing of it and wondering what you guys do?
There are 6 ways to pass multiple object in MVC
ViewModel
Partial View
ViewBag
ViewData
TempData
Tuple
Each one have there own pros and cons.you have to decide base on your issue in hand.
For more information you can refer code project article on it: How to Choose the Best Way to Pass Multiple Models in ASP.NET MVC
Let me give advantage and disadvantage of View Model
ViewModel :
Advantages
ViewModel allows us to render multiple model types in a View as a
single model.
Great intellisense support and compile time error checking on View
page.
ViewModel is good for security purpose also as Views have only what
they exactly need. Core domain models are not exposed to user.
If there is any change in core domain model, you do not need to
change anywhere in View code, just you need to modify corresponding
ViewModel.
Disadvantages
ViewModels add another layer between Models and Views so it increases
the complexity a little bit. So for small and demo applications, we
can use tuple or other ways to keep the things simple for demo.
Option 1:
The best approach is to use strongly typed views with Model or ViewModel.
For Example, you have two classes User and Education, you want to display all education details of user in a view, you can create a custom view model and pass it to view, where you view is strongly typed view model:
public class User
{
public int UserId {get;set;}
public string UserName {get;set}
-------
------
}
public class Education
{
public int UserId {get;set;}
public int DegreeId {get;set;}
public long Marks {get;set;}
---------------
--------------
}
Now create a view Model like this:
public class EducationViewModel
{
public User user {get;set;}
public List<Education> educationList {get;set;}
}
now pass the ViewModel to View and do this in View:
#model AppNameSpace.ViewModels.EducationViewModel
Tip: Create a folder named ViewModels and put all the viewmodel classes in it.
Option2:
Option 2 is to user ViewBag and pass multiple object from control to your view, ViewBag is accessible when you set some value in it in controller, you can access in the view of that action, after that it is automatically washed out, and its null if you access again it.
you can use ViewBag like this:
ViewBag.Message = "Using ViewBag";
and read value like this in View:
string Message = ViewBag.Message as string;
Option 3:
Option 3 is to store data in TempData, its once read only, means you set value in it, and when you read it, its automatically removed, TempData internally uses Session Variables.You can use TempData like this:
TempData["Key"] = "value";
now you read it in view:
string val = TempData["Key"] as string;
after reading it, it will be automatically removed, but you can keep it if you need it further like this:
TempData.Keep("Key");
I've spent quite some time to try and find an elegant solution for the following challenge. I've been unable to find a solution that's more than a hack around the problem.
I've got a simple setup of a View, ViewModel and a Model. I will keep it very simple for the sake of explanation.
The Model has a single property called Title of type String.
The Model is the DataContext for the View.
The View has a TextBlock thats databound to Title on the Model.
The ViewModel has a method called Save() that will save the Model to a Server
The Server can push changes made to the Model
So far so good. Now there are two adjustments I need to make in order to keep the Model in sync with a Server. The type of server is not important. Just know that I need to call Save() in order to push the Model to the Server.
Adjustment 1:
The Model.Title property will need to call RaisePropertyChanged() in order to translate changes made to the Model by the Server to the View. This works nicely since the Model is the DataContext for the View
Not too bad.
Adjustment 2:
Next step is to call Save() to save changes made from the View to the Model on the Server. This is where I get stuck. I can handle the Model.PropertyChanged event on the ViewModel that calls Save() when the Model gets changed but this makes it echo changes made by the Server.
I'm looking for an elegant and logical solution and am willing to change my architecture if it makes sense.
In the past I 've written an application that supports "live" editing of data objects from multiple locations: many instances of the app can edit the same object at the same time, and when someone pushes changes to the server everyone else gets notified and (in the simplest scenario) sees those changes immediately. Here's a summary of how it was designed.
Setup
Views always bind to ViewModels. I know it's a lot of boilerplate, but binding directly to Models is not acceptable in any but the simplest scenarios; it's also not in the spirit of MVVM.
ViewModels have sole responsibility for pushing changes. This obviously includes pushing changes to the server, but it could also include pushing changes to other components of the application.
To do this, ViewModels might want to clone the Models they wrap so that they can provide transaction semantics to the rest of the app as they provide to the server (i.e. you can choose when to push changes to the rest of the app, which you cannot do if everyone directly binds to the same Model instance). Isolating changes like this requires still more work, but it also opens up powerful possibilities (e.g. undoing changes is trivial: just don't push them).
ViewModels have a dependency on some kind of Data Service. The Data Service is an application component that sits between the data store and the consumers and handles all communication between them. Whenever a ViewModel clones its Model it also subscribes to appropriate "data store changed" events that the Data Service exposes.
This allows ViewModels to be notified of changes to "their" model that other ViewModels have pushed to the data store and react appropriately. With proper abstraction, the data store can also be anything at all (e.g. a WCF service in that specific application).
Workflow
A ViewModel is created and assigned ownership of a Model. It immediately clones the Model and exposes this clone to the View. Having a dependency on the Data Service, it tells the DS that it wants to subscribe to notifications for updates this specific Model. The ViewModel does not know what it is that identifies its Model (the "primary key"), but it doesn't need to because that's a responsibility of the DS.
When the user finishes editing they interact with the View which invokes a Command on the VM. The VM then calls into the DS, pushing the changes made to its cloned Model.
The DS persists the changes and additionally raises an event that notifies all other interested VMs that changes to Model X have been made; the new version of the Model is supplied as part of the event arguments.
Other VMs that have been assigned ownership of the same Model now know that external changes have arrived. They can now decide how to update the View having all pieces of the puzzle at hand (the "previous" version of the Model, which was cloned; the "dirty" version, which is the clone; and the "current" version, which was pushed as part of the event arguments).
Notes
The Model's INotifyPropertyChanged is used only by the View; if the ViewModel wants to know whether the Model is "dirty", it can always compare the clone to the original version (if it has been kept around, which I recommend if possible).
The ViewModel pushes changes to the Server atomically, which is good because it ensures that the data store is always in a consistent state. This is a design choice, and if you want to do things differently another design would be more appropriate.
The Server can opt to not raise the "Model changed" event for the ViewModel that was responsible for this change if the ViewModel passes this as a parameter to the "push changes" call. Even if it does not, the ViewModel can choose to do nothing if it sees that the "current" version of the Model is identical to its own clone.
With enough abstraction, changes can be pushed to other processes running on other machines as easily as they can be pushed to other Views in your shell.
Hope this helps; I can offer more clarification if required.
I would suggest adding Controllers to the MVVM mix (MVCVM?) to simplify the update pattern.
The controller listens for changes at a higher level and propagates changes between the Model and ViewModel.
The basic rules to keep things clean are:
ViewModels are just dumb containers that hold a certain shape of data. They do not know where the data comes from or where it is displayed.
Views display a certain shape of data (via bindings to a view model).
They do not know where the data comes from, only how to display it.
Models supply real data. They do not know where it is consumed.
Controllers implement logic. Things like supplying the code for ICommands in VMs, listening for changes to data etc. They populate VMs from Models. It makes sense to have them listen for VM changes and update the Model.
As mentioned in another answer your DataContext should be the VM (or property of it), not the model. Pointing at a DataModel makes it hard to separate concerns (e.g. for Test Driven Development).
Most other solutions put logic in ViewModels which is "not right", but I see the benefits of controllers overlooked all the time. Darn that MVVM acronym! :)
binding model to view directly only works if the model implement INotifyPropertyChanged interface. (eg. your Model generated by Entity Framework)
Model implement INotifyPropertyChanged
you can do this.
public interface IModel : INotifyPropertyChanged //just sample model
{
public string Title { get; set; }
}
public class ViewModel : NotificationObject //prism's ViewModel
{
private IModel model;
//construct
public ViewModel(IModel model)
{
this.model = model;
this.model.PropertyChanged += new PropertyChangedEventHandler(model_PropertyChanged);
}
private void model_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == "Title")
{
//Do something if model has changed by external service.
RaisePropertyChanged(e.PropertyName);
}
}
//....more properties
}
ViewModel as DTO
if Model implements INotifyPropertyChanged(it depends) you may use it as DataContext in most cases. but in DDD most MVVM model will be considered as EntityObject not a real Domain's Model.
more efficient way is to use ViewModel as DTO
//Option 1.ViewModel act as DTO / expose some Model's property and responsible for UI logic.
public string Title
{
get
{
// some getter logic
return string.Format("{0}", this.model.Title);
}
set
{
// if(Validate(value)) add some setter logic
this.model.Title = value;
RaisePropertyChanged(() => Title);
}
}
//Option 2.expose the Model (have self validation and implement INotifyPropertyChanged).
public IModel Model
{
get { return this.model; }
set
{
this.model = value;
RaisePropertyChanged(() => Model);
}
}
both of ViewModel's properties above can be used for Binding while not breaking MVVM pattern (pattern != rule) it really depends.
One more thing..
ViewModel has dependency on Model. if Model can be changed by external service/environment. it's "global state" that make things complicate.
If your only problem is that changes from the server get immediately re-saved, why not do something like the following:
//WARNING: typed in SO window
public class ViewModel
{
private string _title;
public string Title
{
get { return _title; }
set
{
if (value != _title)
{
_title = value;
this.OnPropertyChanged("Title");
this.BeginSaveToServer();
}
}
}
public void UpdateTitleFromServer(string newTitle)
{
_title = newTitle;
this.OnPropertyChanged("Title"); //alert the view of the change
}
}
This code manually alerts the view of the property change from the server without going through the property setter and therefore without invoking the "save to server" code.
The reason you have this problem is because your model doesn't know whether it is dirty or not.
string Title {
set {
this._title = value;
this._isDirty = true; // ??!!
}
}}
The solution is to copy the server changes via a separate method:
public void CopyFromServer(Model serverCopy)
{
this._title = serverCopy.Title;
}
I am doing big project in Web Forms and entered a big mess of code(can be solved with little refactoring), so I decided to take a peek at mvc, seems like everyone favores it over web forms.
I have dll file with all LINQ to SQL classes and methods for existing sql db and I started teaching myself by reacreating this project in mvc.I first recreated my homepage from webforms to razor, so far so good and I recreated one of the user controls to partial view and looped it.
Partial view is strongly typed with one of L2S class, the thing is there is some raw data in it.Like for example My model for partial view is my L2S class PostDetails: it consist od some data ready from output like: Title, Permalink, ViewsNumber etc. but it also cointains some raw data like UserId(I need to call method from dll to get username),DateTimeCreated(on which I also need to call method to get time difference), In webforms I would do this in codebehind but I'm not sure where to do it in mvc, maybe in controller and pass it in ViewData.I am also asking this for future, not just this case.
You should perform those actions in the controller. The controller is exactly what it sounds like, it controls the data flow between the model and the view.
Here is an example using your PostDetails:
PostDetailsModel
String Title {get;set;}
String Permalink {get;set;}
Int ViewNumber {get;set}
Int UserId {get;set}
DateTime DateTimeCreated {get;set;}
GetDetailsView: this will be requested by your user, and will be a visual representation of the PostDetailsModel (however you want to format that). When this View is requested, a call is made to your controller....
PostDetailsController
//This method will (by default) come from calling [BASEURL]/PostDetails/GetDetails
public ActionResult GetDetails()
{
var details = new PostDetailsModel();
details.UserId = GetUserId();
details.ViewNumber = GetViewNumber();
....
//By default this looks for a view in the PostDetails folder
//by the name of your method (GetDetails)
return View(details);
}
Notice how the controller is the router between the model and the view, basically. A note, however, it would be better to fill your model from methods contained within some sort of business layer (however you implement that). Something like var details = BL.GetDetails();
Also, when the user makes requests to save data, then you can do that with another method that takes the data (whether it be the PostDetailsModel or an int or...) and does whatever it needs to do, then it can redirect back to the display action (or wherever you need it to go)
There is a wealth of information on MVC with a simple google search. Here is Microsoft's overview, but the wikipedia article is very succinct if you just want the basics
In MVC, All your requests will be handled by an action method in a controller. and then controller returns a view. So you can get the data in your controller (or a different layer which will be called from the controller) and pass that data to your view.
Strongly typed views are a clean way of doing things. Create a ViewModel for your scenario. Mostly ViewModels looks similar to the Entities. Ex : For Displaying the details about a customer, i will create a viewModel called "CustomerViewModel"
public class CustomerViewModel
{
public string CustomerId { set;get;}
public string FirstName { set;get;}
}
Then in my CustomerController, I will have a get method for the customer
public class CustomersController : Controller
{
public ActionResult Details(int id)
{
CustomerViewModel objCustomer=new CustomerViewModel;
objCustomer.FirstName="Samuel";
//Instead of hardcoding the values here , you can get it
// from the database using the id and assign to the properties
return View(objCustomer);
}
}
And you will have a view called "Details.chtml" in your Views\Customer
folder which is strongly typed to your CustomerViewModel
#model CustomerViewModel
<div>
<h2>#Model.FirstName</h2>
<p>#Model.CustomerId</h2>
</div>
This can be accessed like http://yourdomain.com/Customer/Details/25
Personally i prefer to keep my controller actions thin. so i write the GetFromDatabase code in a seperate service layer and i just call that method from my action method
I think that you'll find this article very useful:
MVC Overview
It explains in detail, as to what each component should be used for:
Models. Model objects are the parts of the application that implement
the logic for the application s data domain. Often, model objects
retrieve and store model state in a database. For example, a Product
object might retrieve information from a database, operate on it, and
then write updated information back to a Products table in SQL Server.
Views. Views are the components that display the application s user
interface (UI). Typically, this UI is created from the model data. An
example would be an edit view of a Products table that displays text
boxes, drop-down lists, and check boxes based on the current state of
a Products object.
Controllers. Controllers are the components that handle user
interaction, work with the model, and ultimately select a view to
render that displays UI. In an MVC application, the view only displays
information; the controller handles and responds to user input and
interaction. For example, the controller handles query-string values,
and passes these values to the model, which in turn queries the
database by using the values.