New and updated information can be found here: <a href="/Documentation:MVC_Generated_ViewModel_UI_in_MDrivenFramework" title="Documentation:MVC Generated ViewModel UI in MDrivenFramework" data-bs-title="Documentation:MVC_Generated_ViewModel_UI_in_MDrivenFramework">MVC_Generated_ViewModel_UI_in_MDrivenFramework</a>
❗🕜 Warning: this article may contain outdated information. Consider before using any descriptions/solutions, otherwise, it still can be helpful. <a href="https://wiki.mdriven.net/index.php/Documentation:MDriven_Product_Line#Synonyms_and_name_changes"> Help: Synonyms and name changes </a>
Even if it is perfectly possible to let MVC use business objects in this way, it is not optimal for a couple of reasons: security, business rules, and overall control of information.
It is preferable to add a layer of abstraction between the model and the view – the view model. The view model can be described as a perspective or section or transformation of parts of the model and offers a good place to mold information from the model in specific formats – like when combining multiple attributes that build up an address to a customer in the model or to a single string that we may want to present in the view.
It is also likely that in large projects with multiple developers that hold different skills – like model-savvy developers and view-savvy developers – the model developer might not “trust” the view developer to access only the “correct” or intended part of the model for the task at hand. Then the View model is a perfect way to define each use case/task/view and only hold the information needed.
View models defined in Modlr are described in multiple articles on this site – but the problem until now – was that they always needed to belong to an EcoSpace. This made it impossible for MVC to instantiate them to send back data from a postback to our controller.
How We Solved It:[<a href="/index.php?title=Documentation:MVC_View_Model_handling&veaction=edit§ion=1" class="mw-editsection-visualeditor" title="Edit section: How We Solved It:" data-bs-title="Documentation:MVC_View_Model_handling">edit</a> | <a href="/index.php?title=Documentation:MVC_View_Model_handling&action=edit§ion=1" title="Edit section: How We Solved It:" data-bs-title="Documentation:MVC_View_Model_handling">edit source</a>]
View models can also now be in Offline mode. They can be code generated for easy static type check and data binding support. They work equally well in MVC, WPF, Silverlight, or whatever your choice of UI layer.
The code generated ViewModel has been cleaned up for this release. If you used them earlier, you will need to adapt your code (we dropped the “Root” from vm.Root.Attribute so that it is now vm.Attribute. Furthermore, the base class VMClass is no longer inheriting Dictionary<>; if you need your vm to act as a dictionary, use the vm.AsDictionary property)
Given this model:
I declare a ViewModel:
And now I can use the standard MVC scaffolding for creating Views:
I also use the standard actions in Visual Studio to create Controllers but change the base class to EcoController (from Peters Sample). Some Controller code examples:
<span style="background: white; color: blue;">public class </span><span style="background: white; color: #2b91af;">ElaborateVMController </span><span style="background: white; color: black;">: </span><span style="background: white; color: #2b91af;">EcoController </span><span style="background: white; color: black;">{ </span><span style="background: white; color: green;">// // GET: /Elaborate/ </span><span style="background: white; color: blue;">public </span><span style="background: white; color: #2b91af;">ActionResult </span><span style="background: white; color: black;">Index() { </span><span style="background: white; color: blue;">var </span><span style="background: white; color: black;">all=EcoSpace.Extents.AllInstances<</span><span style="background: white; color: #2b91af;">ElaborateClass</span><span style="background: white; color: black;">>().</span>
<span style="background: white; color: black;"> Select(o => </span><span style="background: white; color: #2b91af;">ElaborateVM</span><span style="background: white; color: black;">.Create(EcoSpace, o)); </span><span style="background: white; color: blue;">return </span><span style="background: white; color: black;">View(all); } </span><span style="background: white; color: green;">// // GET: /Elaborate/Details/5 </span><span style="background: white; color: blue;">public </span><span style="background: white; color: #2b91af;">ActionResult </span><span style="background: white; color: black;">Details(</span><span style="background: white; color: blue;">string </span><span style="background: white; color: black;">Identity) { </span><span style="background: white; color: #2b91af;">IObject </span><span style="background: white; color: black;">io = EcoSpace.ExternalIds.ObjectForId(Identity); </span><span style="background: white; color: blue;">return </span><span style="background: white; color: black;">View(</span><span style="background: white; color: #2b91af;">ElaborateVM</span><span style="background: white; color: black;">.Create(EcoSpace, io.AsObject </span><span style="background: white; color: blue;">as </span><span style="background: white; color: #2b91af;">ElaborateClass</span><span style="background: white; color: black;">)); } </span><span style="background: white; color: green;">// // POST: /Elaborate/Create </span><span style="background: white; color: black;">[</span><span style="background: white; color: #2b91af;">HttpPost</span><span style="background: white; color: black;">] </span><span style="background: white; color: blue;">public </span><span style="background: white; color: #2b91af;">ActionResult </span><span style="background: white; color: black;">Create(</span><span style="background: white; color: #2b91af;">ElaborateVM </span><span style="background: white; color: black;">offlineElaborateVM) { </span><span style="background: white; color: blue;">try </span><span style="background: white; color: black;">{ </span><span style="background: white; color: #2b91af;">ViewModelHelper</span><span style="background: white; color: black;">.ApplyValues(offlineElaborateVM, </span>
<span style="background: white; color: #2b91af;">ElaborateVM</span><span style="background: white; color: black;">.Create(EcoSpace, </span><span style="background: white; color: blue;">new </span><span style="background: white; color: #2b91af;">ElaborateClass</span><span style="background: white; color: black;">(EcoSpace)), </span><span style="background: white; color: blue;">null</span><span style="background: white; color: black;">); </span><span style="background: white; color: blue;">if </span><span style="background: white; color: black;">(Commit()) </span><span style="background: white; color: blue;">return </span><span style="background: white; color: black;">RedirectToAction(</span><span style="background: white; color: #a31515;">"Index"</span><span style="background: white; color: black;">); </span><span style="background: white; color: blue;">return </span><span style="background: white; color: black;">View(); } </span><span style="background: white; color: blue;">catch </span><span style="background: white; color: black;">{ </span><span style="background: white; color: blue;">return </span><span style="background: white; color: black;">View(); } } </span>
and an example of the scaffolded View code:
<span style="background: yellow; color: black;">@model </span><span style="background: white; color: black;">EcoMVC.ViewModelCodeGen_ElaborateVM.</span><span style="background: white; color: #2b91af;">ElaborateVM </span><span style="background: yellow; color: black;">@{ </span><span style="background: white; color: black;"> ViewBag.Title = </span><span style="background: white; color: #a31515;">"Details"</span><span style="background: white; color: black;">; </span><span style="background: yellow; color: black;">} </span><span style="background: white; color: blue;"><</span><span style="background: white; color: maroon;">h2</span><span style="background: white; color: blue;">></span><span style="background: white; color: black;">Details</span><span style="background: white; color: blue;"></</span><span style="background: white; color: maroon;">h2</span><span style="background: white; color: blue;">> <</span><span style="background: white; color: maroon;">fieldset</span><span style="background: white; color: blue;">> <</span><span style="background: white; color: maroon;">legend</span><span style="background: white; color: blue;">></span><span style="background: white; color: black;">ElaborateVM</span><span style="background: white; color: blue;"></</span><span style="background: white; color: maroon;">legend</span><span style="background: white; color: blue;">> <</span><span style="background: white; color: maroon;">div </span><span style="background: white; color: red;">class</span><span style="background: white; color: blue;">="display-label"> </span><span style="background: yellow; color: black;">@</span><span style="background: white; color: black;">Html.DisplayNameFor(model => model.Attribute1) </span><span style="background: white; color: blue;"></</span><span style="background: white; color: maroon;">div</span><span style="background: white; color: blue;">> <</span><span style="background: white; color: maroon;">div </span><span style="background: white; color: red;">class</span><span style="background: white; color: blue;">="display-field"> </span><span style="background: yellow; color: black;">@</span><span style="background: white; color: black;">Html.DisplayFor(model => model.Attribute1) </span><span style="background: white; color: blue;"></</span><span style="background: white; color: maroon;">div</span><span style="background: white; color: blue;">> <</span><span style="background: white; color: maroon;">div </span><span style="background: white; color: red;">class</span><span style="background: white; color: blue;">="display-label"> </span><span style="background: yellow; color: black;">@</span><span style="background: white; color: black;">Html.DisplayNameFor(model => model.Attribute2) </span><span style="background: white; color: blue;"></</span><span style="background: white; color: maroon;">div</span><span style="background: white; color: blue;">> <</span><span style="background: white; color: maroon;">div </span><span style="background: white; color: red;">class</span><span style="background: white; color: blue;">="display-field"> </span><span style="background: yellow; color: black;">@</span><span style="background: white; color: black;">Html.DisplayFor(model => model.Attribute2) </span><span style="background: white; color: blue;"></</span><span style="background: white; color: maroon;">div</span><span style="background: white; color: blue;">> </span>
It ends up looking like this:
Attributes in Generated Code[<a href="/index.php?title=Documentation:MVC_View_Model_handling&veaction=edit§ion=2" class="mw-editsection-visualeditor" title="Edit section: Attributes in Generated Code" data-bs-title="Documentation:MVC_View_Model_handling">edit</a> | <a href="/index.php?title=Documentation:MVC_View_Model_handling&action=edit§ion=2" title="Edit section: Attributes in Generated Code" data-bs-title="Documentation:MVC_View_Model_handling">edit source</a>]
Oh – before I forget – you probably want to decorate the ViewModel attributes with specific MVC attributes like [Required]. In Modlr, all tagged values that start with a star “*” are added to the generated code. This:
on a ViewModel column, will come out as:
<span style="background: white; color: black;"> <span style="background-color: #ffff00;">[System.ComponentModel.DataAnnotations.</span></span><span style="background: white; color: #2b91af;"><span style="background-color: #ffff00;">Required</span></span><span style="background: white; color: black;"><span style="background-color: #ffff00;">()]</span> [</span><span style="background: white; color: #2b91af;">GeneratedCodeAttribute</span><span style="background: white; color: black;">(</span><span style="background: white; color: #a31515;">"ECO"</span><span style="background: white; color: black;">, </span><span style="background: white; color: #a31515;">"6.0.0.0"</span><span style="background: white; color: black;">)] </span><span style="background: white; color: blue;">public string </span><span style="background: white; color: black;">Attribute1 { </span><span style="background: white; color: blue;">get </span><span style="background: white; color: black;">{ </span>
And that will be picked up by MVC as:
(Swedish for Field Attribute1 is required)
Taking It Further[<a href="/index.php?title=Documentation:MVC_View_Model_handling&veaction=edit§ion=3" class="mw-editsection-visualeditor" title="Edit section: Taking It Further" data-bs-title="Documentation:MVC_View_Model_handling">edit</a> | <a href="/index.php?title=Documentation:MVC_View_Model_handling&action=edit§ion=3" title="Edit section: Taking It Further" data-bs-title="Documentation:MVC_View_Model_handling">edit source</a>]
As I said earlier, I am still no MVC expert. I can see the merits of MVC but I am also still confused about all the name-matching that is going on behind the scenes. I would be grateful to have someone do a better sample and share it here…