aspnetmvc-14721-common-features-templates.md
Templates allow you to quickly extend built-in functionality and introduce new capabilities with minimum effort. The DevExpress MVC extensions provide you with the ability to create templates for various extension elements.
Templates can be defined at different object levels at the same time (e.g., at the extension level and the item level). In this case, templates created at a lower level in the logical tree take precedence over other templates for the same element created at a higher level (e.g., a template defined at the item level has precedence over the same element template created at the extension level).
The Set [ElementName] TemplateContent methods are provided to define an element template.
For each template type you want to use, create a Partial View (a .cshtml or .vbhtml) and provide it with the required content markup. To use this Partial View within a template, call the Html.RenderPartial helper method in template implementation.
Note that the method delegates that enable you to implement templates give you access to a container object within which a template is instantiated. A template container object typically exposes useful information identifying the templated element (for instance, for a grid column header these might be the corresponding column, the header’s current location - in the header section, Group Panel, or Customization Window, etc.). Depending upon your application logic, you may or may not use this information when composing templates. The following options are available.
If a template is simple and its content does not depend on the information provided by a template container, you do not have to pass a template container object to a partial view. You can define the template contents by using a HTML markup.
View:
@Html.DevExpress().Menu(settings => {
settings.Name = "myMenu";
settings.Items.Add("Google", "google", "", "http://www.google.com/");
settings.Items.Add().SetTextTemplateContent(container => {
Html.RenderPartial("MyMenuItem"); });
}).GetHtml()
@Html.DevExpress().Menu( _
Sub(settings)
settings.Name = "myMenu"
settings.Items.Add("Google", "google", "", "http://www.google.com/")
settings.Items.Add().SetTextTemplateContent( _
Sub(container)
Html.RenderPartial("MyMenuItem")
End Sub)
End Sub).GetHtml()
Partial View (“MyMenuItem”):
<a href="http://www.bing.com/">Bing</a>
Note that you can do this more easily by using another method overload that accepts a string as a parameter.
View:
@Html.DevExpress().Menu(settings => {
settings.Name = "myMenu";
settings.Items.Add("Google", "google", "", "http://www.google.com/");
settings.Items.Add().SetTextTemplateContent("<a href='http://www.bing.com/'>Bing</a>");
}).GetHtml()
@Html.DevExpress().Menu( _
Sub(settings)
settings.Name = "myMenu"
settings.Items.Add("Google", "google", "", "http://www.google.com/")
settings.Items.Add().SetTextTemplateContent("<a href='http://www.bing.com/'>Bing</a>")
End Sub).GetHtml()
If you dynamically compose a template based on template container information, you can pass a template container object to a partial view page as a Model. Use the Html.RenderPartial method’s model parameter for this purpose.
View:
@Html.DevExpress().Menu(settings => {
settings.Name = "myMenu";
settings.Items.Add("Google", "google", "", "http://www.google.com/");
settings.Items.Add("Bing", "bing", "", "http://www.bing.com/");
settings.SetItemTextTemplateContent(container => {
Html.RenderPartial("MyMenuItem", container);
});
}).GetHtml()
@Html.DevExpress().Menu( _
Sub(settings)
settings.Name = "myMenu"
settings.Items.Add("Google", "google", "", "http://www.google.com/")
settings.Items.Add("Bing", "bing", "", "http://www.bing.com/")
settings.SetItemTextTemplateContent( _
Sub(container)
Html.RenderPartial("MyMenuItem", container)
End Sub)
End Sub).GetHtml()
Partial View (“MyMenuItem”):
@model MenuItemTemplateContainer
<a [email protected]>
@if (Model.Item.Name == "bing") { <b>Try @Model.Item.Text</b> }
else { @Model.Item.Text }
</a>
@ModelType MenuItemTemplateContainer
<a [email protected]>
@Code
If (Model.Item.Name = "bing") Then
@<b>Try @Model.Item.Text</b>
Else
@Model.Item.Text
End If
End Code
</a>
You can also pass a template container object to a partial view page as a part of the ViewData by using the Html.RenderPartial method’s viewData parameter.
View:
@Html.DevExpress().Menu(settings => {
settings.Name = "myMenu";
settings.Items.Add("Google", "google", "", "http://www.google.com/");
settings.Items.Add("Bing", "bing", "", "http://www.bing.com/");
settings.SetItemTextTemplateContent(container => {
ViewData["Container"] = container;
Html.RenderPartial("MyMenuItem", ViewData);
});
}).GetHtml()
@Html.DevExpress().Menu( _
Sub(settings)
settings.Name = "myMenu"
settings.Items.Add("Google", "google", "", "http://www.google.com/")
settings.Items.Add("Bing", "bing", "", "http://www.bing.com/")
settings.SetItemTextTemplateContent( _
Sub(container)
ViewData("Container") = container
Html.RenderPartial("MyMenuItem", ViewData)
End Sub)
End Sub).GetHtml()
Partial View (“MyMenuItem”):
@{ var container = ViewData["Container"] as MenuItemTemplateContainer; }
<a [email protected]>
@if (container.Item.Name == "bing") { <b>Try @container.Item.Text</b> }
else { @container.Item.Text }
</a>
@Code
Dim container = CType(ViewData("Container"), MenuItemTemplateContainer)
End Code
<a [email protected]>
@Code
If (container.Item.Name = "bing") Then
@<b>Try @container.Item.Text</b>
Else
@container.Item.Text
End If
End Code
</a>
If you do not want to use partial views for some reason, and need to entirely define template contents within a delegate method implementation, you can do this using the following options.
You can safely compose a template with the use of DevExpress extensions, which can be rendered with either the ExtensionBase.Render or ExtensionBase.GetHtml method.
View:
@Html.DevExpress().Menu(settings => {
settings.Name = "myMenu";
settings.Items.Add().SetTextTemplateContent(container => {
Html.DevExpress().Label(labelSettings => {
labelSettings.Text = "Google";
}).GetHtml();
});
settings.Items.Add().SetTextTemplateContent(container =>{
Html.DevExpress().HyperLink(linkSettings => {
linkSettings.Properties.Text = "Bing";
linkSettings.NavigateUrl = "http://www.bing.com/";
}).Render();
});
}).GetHtml()
@Html.DevExpress().Menu( _
Sub(settings)
settings.Name = "myMenu"
settings.Items.Add().SetTextTemplateContent( _
Sub(container)
Html.DevExpress().Label( _
Sub(labelSettings)
labelSettings.Text = "Google"
End Sub).GetHtml()
End Sub)
settings.Items.Add().SetTextTemplateContent( _
Sub(container)
Html.DevExpress().HyperLink( _
Sub(linkSettings)
linkSettings.Properties.Text = "Bing"
linkSettings.NavigateUrl = "http://www.bing.com/"
End Sub).Render()
End Sub)
End Sub).GetHtml()
If you need to use expressions and an HTML markup, and then combine them with server code within template contents, you can embed a HTML markup by using the ViewContext.Writer.Write method.
View:
@Html.DevExpress().Menu(settings => {
settings.Name = "myMenu";
settings.Items.Add("Google", "google", "", "http://www.google.com/");
settings.Items.Add("Bing", "bing", "", "http://www.bing.com/");
settings.SetItemTextTemplateContent(container => {
if (container.Item.Name == "bing"){
ViewContext.Writer.Write("<a href=" + @container.Item.NavigateUrl + "><b>" + Html.Label("", "Try " + @container.Item.Text) + "</b></a>");
}
else {
Html.DevExpress().HyperLink(linkSettings =>{
linkSettings.Properties.Text = container.Item.Text;
linkSettings.NavigateUrl = container.Item.NavigateUrl;
}).Render();
}
});
}).GetHtml()
@Html.DevExpress().Menu( _
Sub(settings)
settings.Name = "myMenu"
settings.Items.Add("Google", "google", "", "http://www.google.com/")
settings.Items.Add("Bing", "bing", "", "http://www.bing.com/")
settings.SetItemTextTemplateContent( _
Sub(container)
If (container.Item.Name = "bing") Then
ViewContext.Writer.Write("<a href=" & container.Item.NavigateUrl & "><b>" & Html.Label("", "Try " & container.Item.Text).ToHtmlString() & "</b></a>")
Else
Html.DevExpress().HyperLink( _
Sub(linkSettings)
linkSettings.Properties.Text = container.Item.Text
linkSettings.NavigateUrl = container.Item.NavigateUrl
End Sub).Render()
End If
End Sub)
End Sub).GetHtml()
You can implement an extension method for the HtmlHelper in order to access it in the Controller (not a View) scope. To implement this functionality, you may pass an HtmlHelper object to some static method that creates DevExpress extension settings with templates. At first, you may create some class to get extension settings shared between Views.
Controller code:
public static class GridViewHelper {
public static GridViewSettings GetInlineEditingSettings(this HtmlHelper htmlHelper){
GridViewSettings settings = new GridViewSettings();
settings.Name = "gvEditingWithTemplate";
settings.KeyFieldName = "ProductID";
...
settings.SetEditFormTemplateContent(c => {
var product = htmlHelper.ViewData["EditableProduct"] != null ? htmlHelper.ViewData["EditableProduct"] : c.DataItem;
htmlHelper.ViewContext.Writer.Write(
"<div class=\"edit_form\">" +
"<div class=\"line\">"
);
htmlHelper.DevExpress().Label(
edtSettings => {
edtSettings.ControlStyle.CssClass = "label";
edtSettings.Text = "Product Name:";
edtSettings.AssociatedControlName = "ProductName";
}).Render();
htmlHelper.DevExpress().TextBox(
edtSettings => {
edtSettings.Name = "ProductName";
edtSettings.ControlStyle.CssClass = "editor";
edtSettings.ShowModelErrors = true;
}).Bind(DataBinder.Eval(product, "ProductName")).Render();
htmlHelper.ViewContext.Writer.Write(
"</div>" +
"<div class=\"line\">"
);
...
});
return settings;
}
}
Imports System.Runtime.CompilerServices
Module GridViewHelper
<Extension()>
Function GetInlineEditingSettings(ByVal htmlHelper As HtmlHelper) As GridViewSettings
Dim settings As GridViewSettings = New GridViewSettings()
settings.Name = "gvEditingWithTemplate"
settings.KeyFieldName = "ProductID"
settings.SetEditFormTemplateContent(Function(c)
Dim product = If(htmlHelper.ViewData("EditableProduct") IsNot Nothing, htmlHelper.ViewData("EditableProduct"), c.DataItem)
htmlHelper.ViewContext.Writer.Write("<div class=""edit_form"">" & "<div class=""line"">")
htmlHelper.DevExpress().Label(Function(edtSettings)
edtSettings.ControlStyle.CssClass = "label"
edtSettings.Text = "Product Name:"
edtSettings.AssociatedControlName = "ProductName"
End Function).Render()
htmlHelper.DevExpress().TextBox(Function(edtSettings)
edtSettings.Name = "ProductName"
edtSettings.ControlStyle.CssClass = "editor"
edtSettings.ShowModelErrors = True
End Function).Bind(DataBinder.Eval(product, "ProductName")).Render()
htmlHelper.ViewContext.Writer.Write("</div>" & "<div class=""line"">")
End Function)
Return settings
End Function
End Module
After writing methods to get the settings, you may use this class in various Partial Views as your needs dictate.
Partial view code (ASPX):
@{
var grid = Html.DevExpress().GridView(Html.GetInlineEditingSettings());
if(ViewData["EditError"] != null){
grid.SetEditErrorText((string)ViewData["EditError"]);
}
}
@grid.Bind(Model).GetHtml()