CrossHelper extension method
The CrossHelper extension method returns am HtmlHelper<M> based on a model different from the one the View is strongly typed with. It is useful, when one needs to post the View to a controller that uses a different
ViewModel. Its signature is:
public static HtmlHelper<T> CrossHelper<T>(
this HtmlHelper htmlHelper,
T crossViewModel, string prefix = "")
Where crossViewModel is the other ViewModel, and prefix, if specified, is added as prefix to all input fields names. prefix is usefull when
crossViewModel is only a part of the ViewModel of the Action Method that receives the Post.
In-Line Transformations
All Mvc controls toolkit controls are based on the idea of model transformation. That is, a part of ViewModel is transformed into another object that is more adequate to the way data have to be displayed, and then, when the View is posted, the inverse transformation
is applied to get the original data type filled with the user input. More details on this subject can be found in the section that explains how to define new controls
here. We remember just that both the direct and the inverse transformations are specified by providing an implementation of the
IDisplayModel interface.
In the section Client
Block complete example we presented an example where we allows the user to edit a list of keywords of the ViewModel in a ListBox by specifying a a class that is serialized in Javascript and used as client-side ViewModel. To
achieve this we need to add to the original keyword list a new property of type string that is used to contain the new keywords to add to the list and another string list to contain all keywords selected by the user in the ListBox(selection is used to specify
the items to be removed).
Thus, in order to achieve our goal we need to transform the initial strings list into a complex object with three properties, and then, when the view is posted, to extract again the keywords list edited by the user to fill the original property of the ViewModel.
As a first step we need to implent the complex object and let it implements the IDisplayModel interface:
public class ClientViewModel:IDisplayModel
{
public List<string> Keywords { get; set; }
public List<string> SelectedKeywords { get; set; }
public string ItemToAdd { get; set; }
public ClientViewModel()
{
SelectedKeywords = new List<string>();
ItemToAdd = "";
}
public object ExportToModel(Type TargetType, params object[] context)
{
return Keywords;
}
public void ImportFromModel(object model, params object[] context)
{
Keywords = model as List<string>;
if (Keywords == null)
Keywords = new List<string>();
}
}
ImportFromModel is the direct transformation and ExportToModel the inverse one. In our case both transformations are very simple. The first one just take the original keyword list of the ViewModel and store it in the
Keywords property of our ClientViewModel class, while the inverse transformation just takes the
Keywords property of the above class that contains the list after the user editing and returns it to the original ViewModel. Now suppose that the origina keyword list is contained in a property of the ViewModel called
ClientKeywords:
<%
var clientKeywordsHelper =
Html.TransformedHelper(
m => m.ClientKeywords,
new ClientViewModel()); %>
The above instruction create an instance of HtmlHelper<ClientViewModel> that can be used to render all properties of the
ClientViewModel class and returns it into the clientKeywordsHelper variable. What we need to do is just to use this HtmlHelper as it were the original HttmlHelper of our View, the
Mvc Controls Toolkit willl automatically do the job of applying both the direct and the inverse transformation when needed.
The full code of the example is in the Client Block complete example section. If you need to refer from JavaScript
code to the id of input fields that have been rendered with helpers returned by in-line transformations please see the PrefixedId helper.
The TransformedHelper extension method renders in the page some information about the transformation we have carried out and return the new helper. During the post the information about the transformation applied, is used by the model
binder in order to rebuild the original model. If you need more control on where such information is rendered within the page you can use the
Html.TransformHelper extension method that return the information about the transformation as an
MvcHtmlString, so you can decide where to put it, and pass the new helper as an output parameter:
public static MvcHtmlString TransformHelper<VM, M, NM>(
this HtmlHelper<VM> htmlHelper,
Expression<Func<VM, M>> expression,
NM newModel,
out HtmlHelper<NM> newHtmlHelper,
params object[] args)
where NM : IDisplayModel
If our transformation is encoded by an implementation of the IUpdateModel
Interface instead than an implementation of IDisplayModel, we can get a new helper by using
TransformedUpdateHelper instead of TransformedHelper, or TransformUpdateHelper instead of
TransformHelper, and passing them an expression that selects the DataType to transform as first argument, and an instance of the
IUpdateModel implementation as second argument. See Core Functions: Defining Your Controls! for more information on the use
of the IUpdateModel interface.