Viewdata
And viewmodel Now we will further expand dinnerscontroller to implement rich form editing functions. Here we will discuss two methods to pass data from the Controller to view: viewdata and viewmodel.
From Controller
Transfer Data to view
View Template A typical feature of the MVC pattern is strict functional isolation. The model, Controller, and view define roles and responsibilities, and communicate with each other in a defined manner. This helps improve Testing Performance and Code Reuse. When the Controller decides to present the HTML response to the client, it is responsible for explicitly passing all the required data to the view template. View templates never execute any data queries or applications Program Logic-only responsible for presenting the data transmitted by the model or controller. Currently, the model data passed by the dinnerscontroller to the view template is very simple and the direct-index () method is the list of dinner objects, details (), edit (), create () and the delete () method is to pass a dinner object. When more UI features are added, we often need to pass more data and display the HTML response in the view template. For example, you need to change the country field in the edit and create views (from the HTML text box to the drop-down list box ). We will generate a dynamic list of supported countries, rather than a hardcoded drop-down list box in the view template. We need to pass the dinner object and the list of supported countries to the view template from the Controller at the same time. Let's take a look at the implementation in two ways.
Use viewdata
Dictionary The controller base class exposes a viewdata dictionary attribute to pass additional data from controllers to the Views. For example, to change the country text box in the edit view to a drop-down list box, we update the Edit () Action method and input a selectlist object (except the dinner object ), this object will be used as the model class of the country drop-down list box. // // Get:/dinners/edit/2 Public ActionresultEdit (IntID) { DinnerDinner = dinnerrepository. getdinner (ID ); Viewdata ["Countries"] =New Selectlist(Phonevalidator. Countries, dinner. Country ); ReturnView (dinner ); } The selectlist constructor receives two parameters. The first is the country list, the drop-down list is added, and the second is the selected value. Next, we will update the edit. aspx view template and use the HTML. dropdownlist () helper code html. Textbox () helper method: <% = Html. dropdownlist ("Country", Viewdata ["Countries"]As Selectlist)%> The preceding HTML. the dropdownlist () auxiliary method receives two parameters. The first is the name of the output HTML form element, and the second is the selectlist model class passed in through the viewdata dictionary, you must use the C # keyword as to convert dictionary to selectlist. Now we access/dinners/edit/2 in the browser and find that the country text box in the edit view template has been updated to the drop-down list box.
Because we will also present the edit view template from the http post Edit Method (if there is an error, otherwise we will enter the details view template), so we also need to update the http post Edit Method, when an error occurs to enter the edit view template, add selectlist to viewdata. The Code is as follows: // Get:/dinners/edit/2 Public ActionresultEdit (IntID) { DinnerDinner = dinnerrepository. getdinner (ID ); Viewdata ["Countries"] =New Selectlist(Phonevalidator. Countries, dinner. Country ); ReturnView (dinner ); } // // Post:/dinners/edit/2 [Acceptverbs(Httpverbs. Post)] Public ActionresultEdit (IntID,FormcollectionFormvalues) { DinnerDinner = dinnerrepository. getdinner (ID ); Try { Updatemodel (dinner ); Dinnerrepository. Save (); ReturnRedirecttoaction ("Details",New{Id = dinner. dinnerid }); } Catch { Modelstate. addruleviolations (dinner. getruleviolations ());
Viewdata ["Countries"] =New Selectlist(Phonevalidator. Countries, dinner. Country ); ReturnView (dinner ); } } Now the Edit Method in the dinnerscontroller fully supports the drop-down list box.
Use viewmodel
Mode The advantage of the viewdata dictionary method is that it is very fast and easy to implement. Some developers do not like to use string-based dictionaries. Some input errors may cause errors, but cannot be found during compilation. When you use a strong type in a view template, the as operator or type conversion is also required for a non-strong viewdata dictionary. Another optional method is the viewmodel mode. When this mode is available, we need to create a strong class for a specific view to expose the dynamic parameter values or content required by the view template. The Controller class then fills in and passes these classes to the view template for use. In this way, you can implement type security, check during compilation, and intelligent editor prompts. For example, for the edit view of dinner, we create a dinnerformviewmodel class that exposes two strong attributes: Dinner object and selectlist model class (used to fill the country drop-down list box ). Public class Dinnerformviewmodel { // Properties Public Dinner Dinner { Get ; Private set ;} Public Selectlist Countries { Get ; Private set ;} // Constructor Public Dinnerformviewmodel ( Dinner Dinner ){ Dinner = dinner; Countries = New Selectlist ( Phonevalidator . Allcountries, Dinner. Country ); } } Next, we update the Edit () Action method and use the dinner object retrieved from repository to create the dinnerformviewmodel object and pass it to the view template: // // Get:/dinners/edit/5 Public Actionresult Edit ( Int ID ){ Dinner Dinner = dinnerrepository. getdinner (ID ); Return View ( New Dinnerformviewmodel (Dinner )); } Next, update the view template. in the edit. ASPX page file, change the inherits attribute at the top Inherits = "System. Web. MVC. viewpage <nerddinner. Models. Dinner> Change Inherits = "System. Web. MVC. viewpage <nerddinner. controllers. dinnerformviewmodel> Once the preceding operations are completed, the smart prompt for the model attribute in the view template will be updated to the passed dinnerformviewmodel object model:
Next we need to update the code in the view. The names of HTML elements in the form do not need to be updated, but are still maintained as title and country. We need to update the HTML auxiliary method and use the dinnerformviewmodel class to obtain the attribute values. < P > < Label For = "Title"> Dinner title: </ Label > <% = Html. Textbox ( "Title" , Model. Dinner. Title) %> <% = Html. validationmessage ( "Title" , "*" ) %> </ P > < P > < Label For = "Country"> Country: </ Label > <% = Html. dropdownlist ( "Country" , Model. Countries) %> <% = Html. validationmessage ( "Country" , "*" ) %> </ P > Similarly, we also need to update the edit POST method. When an error occurs, use the dinnerformviewmodel class to pass it to the view template: // // Post:/dinners/edit/5 [ Acceptverbs ( Httpverbs . Post)] Public Actionresult Edit ( Int ID, Formcollection Collection ){ Dinner Dinner = dinnerrepository. getdinner (ID ); Try { Updatemodel (dinner ); Dinnerrepository. Save (); Return Redirecttoaction ( "Details" , New {Id = dinner. dinnerid }); } Catch { Modelstate. addmodelerrors (dinner. getruleviolations ());
Return
View (
New
Dinnerformviewmodel
(Dinner )); } } We also updated the CREATE () Action method and reused the same dinnerformviewmodel class to implement the country drop-down list box in the view. The following is the implementation code of the HTTP-GET: // // Get:/dinners/create Public Actionresult Create (){ Dinner Dinner = New Dinner (){ Eventdate = Datetime . Now. adddays (7) }; Return View ( New Dinnerformviewmodel (Dinner )); } The following is the implementation code of the HTTP-POST create method: // // Post:/dinners/create [ Acceptverbs ( Httpverbs . Post)] Public Actionresult Create ( Dinner Dinner ){ If (Modelstate. isvalid ){ Try { Dinner. hostedby = "Someuser" ; Dinnerrepository. Add (dinner ); Dinnerrepository. Save (); Return Redirecttoaction ( "Details" , New {Id = dinner. dinnerid }); } Catch { Modelstate. addmodelerrors (dinner. getruleviolations ()); } } Return View ( New Dinnerformviewmodel (Dinner )); } Now both the edit and create views Support selecting countries through the following list box.
Custom viewmodel
Class (custom-shaped viewmodel classes
) In the preceding Implementation Scheme, the dinnerformviewmodel class directly discloses two public attributes: Dinner model object and selectlist model attribute. This method is suitable for scenarios where the HTML user interface elements in the view template are close to the Business Model objects. If this is not the case, you can consider creating a custom viewmodel class, create an optimized Object Model Based on the usage of the view-this object model may be completely different from the underlying business model object (domain model object ). For example, the viewmodel class may expose different attributes or aggregate attributes from multiple model objects. The custom viewmodel class can be used not only to transmit data from the Controller to the view for rendering, but also to process the data of the Action Method submitted back from the form to the Controller. In the latter case, you can let the action method update the viewmodel object based on the data submitted by the form, and then use the viewmodel instance to map or obtain the business model object (domain model object) of the time ). The custom viewmodel class provides great flexibility. At any time, when you find that the form submission code in the rendering code or action method in the view template is getting increasingly complicated, you can consider using a custom viewmodel. Generally, this means that the business model object is inconsistent with the user interface elements in the view, and the custom viewmodel class of an intermediary can play a role.