Fundamentals

NOTE
At the time of version 16.1, DevExtreme ASP.NET MVC Wrappers were in the Community Technology Preview (CTP) status. Currently, this product changed its status to Release Candidate (RC). Renewed documentation is available since version 16.2.

DevExtreme ASP.NET MVC Wrappers are a set of server-side wrappers that allow you to configure JavaScript-based DevExtreme widgets using familiar Razor syntax. The Razor constructions are rendered into the HTML and JavaScript needed to initialize a DevExtreme widget.

DevExtreme HTML5 ASPNET MVCWrappers

This guide offers the basics in DevExtreme ASP.NET MVC Wrappers, such as creating and configuring a DevExtreme widget, handling the events and implementing templates.

See Also

Creating a Widget

To create any DevExtreme widget, begin with calling the DevExtreme() HtmlHelper extension method. Then, call the builder method corresponding to the widget you want to create.

@(Html.DevExtreme()
    .Button() // creates the **Button** widget
)

Specifying the Options

DevExtreme ASP.NET MVC Wrappers mirror the options of the client-side widgets with only one difference: instead of the lower camel case usual in JavaScript, wrapper methods use the upper camel case common in .NET. For example:

Widget Option Wrapper Method
dataSource DataSource
tooltip Tooltip
showColumnHeaders ShowColumnHeaders

Wrapper methods are called using a fluent interface. In Visual Studio, IntelliSense prompts you the names of available methods, their accepted values and short descriptions.

DevExtreme HTML5 ASPNET MVCWrappers

To specify a simple widget option, call the corresponding wrapper method and pass the required option value.

@(Html.DevExtreme().Button()
    .ID("submitButton") // sets the "id" attribute of the widget container
    .Text("submit") // sets the button text
    .Width(100) // sets the button width
)
NOTE
Specifying the ID option is not necessary, however, you may need it if you plan to access the widget JavaScript API at runtime (to call a method, for example). The value of the ID option should meet certain requirements. It must always be unique in the context of a page. If a partial view is loaded multiple times, each instance of this partial view must render all widgets with unique IDs. Also, the value of the ID option should meet the requirements for the id attribute in HTML5.

Nested options are configured using lambda expressions. A lambda parameter starts a new chain of methods that specify the nested options.

@(Html.DevExtreme().Chart()
    .Legend(l => l // configures the chart legend (l - lambda parameter)
        .Visible(false) // hides the legend in the chart
    )
    .Tooltip(t => t // configures the tooltip (t - lambda parameter)
        .Enabled(true) // enables the tooltip
        .Font(f => f // configures the tooltip's text (f - lambda parameter)
            .Color("blue") // paints the tooltip's text in blue
        )
    )
)

Options that represent collections of items are configured using lambda expressions as well, but in this case, the lambda parameter performs the role of an item factory. Its Add() method adds a new item to the collection and then returns it for further configuration by the chain that follows.

@(Html.DevExtreme().DataGrid()
    .Columns(columns => { // specifies a collection of columns
        columns.Add() // adds the "CustomerID" column
            .DataField("CustomerID");

        columns.Add() // adds the "OrderDate" column
            .DataField("OrderDate")
            .DataType(GridColumnDataType.Date);
    })
)

Options that accept a predefined set of values are specified by .NET enums.

@(Html.DevExtreme().DateBox()
    .Format(DateBoxFormat.Datetime) // sets the format using the DateBoxFormat .NET enum
)

More examples on each case are available in our sample application.

Handling Events and Defining Callbacks

Event handlers and callbacks are defined by JavaScript functions which can be specified in the following manners.

  • A short inline function.

    @(Html.DevExtreme().Button()
        .OnClick("function () { alert('The button was clicked'); }")
    )
    
    
    @(Html.DevExtreme().VectorMap()
        .Tooltip(t => t
            .CustomizeTooltip("function (arg) { return { text: arg.attribute('text') } }")
        )
    )
  • An external function.

    @(Html.DevExtreme().Button()
        .OnClick("myButton_click")
    )
    
    
    @(Html.DevExtreme().VectorMap()
        .Tooltip(t => t
            .CustomizeTooltip("vectorMap_tooltip_customizeTooltip")
        )
    )
    
    
    <script>
        function myButton_click() {
            alert("The button was clicked");
        }
        function vectorMap_tooltip_customizeTooltip (arg) {
            return { text: arg.attribute("text") };
        }
    </script>
  • A function wrapped into the Razor <text> tag.

    @(Html.DevExtreme().Button()
        .OnClick(@<text>
            function () {
                alert("The button was clicked");
            }
        </text>)
    )
    
    
    @(Html.DevExtreme().VectorMap()
        .Tooltip(t => t
            .CustomizeTooltip(@<text>
                function (arg) {
                    return { text: arg.attribute("text") };
                }
            </text>)
        )
    )

Calling Methods

To call widget methods, use JavaScript, much like you did to handle widget events. For instance, let's say you have a Popup widget.

@(Html.DevExtreme().Popup()
    .ID("popup")
)

This widget appears on the page only after its show() method was called. The following code demonstrates how to call this method.

$("#popup").dxPopup("show");

You can put this code in any JavaScript constructions and execute it whenever you need to, for example, when a user clicks a button...

// ...
@(Html.DevExtreme().Button()
    .OnClick("showPopup")
)
<script>
    function showPopup() {
        $("#popup").dxPopup("show");
    }
</script>

... or once your page is ready.

// ...
<script>
    $(showPopup);

    function showPopup() {
        $("#popup").dxPopup("show");
    }
</script>

If the method you are calling accepts arguments, pass them after the method's name. For example, the following code calls the toggle(showing) method of the Popup widget with true as an argument.

$("#popup").dxPopup("toggle", true);
See Also
  • API Reference | WidgetName | Methods - lists all methods of a specific DevExtreme widget.

Implementing Templates

There are two types of templates in DevExtreme ASP.NET MVC Wrappers.

  • Simple templates
    Simple templates are very common. They are used extensively in lists, menus, select boxes and other collections. For example, the following code specifies a template for items in the List widget.

    @(Html.DevExtreme().List()
        // ...
        .ItemTemplate(@<text>
            <div><%= ProductName %></div>
        </text>)
    )

    Note that this template is wrapped in the @<text> ... </text> Razor code construction and uses templating syntax provided by Underscore.js. The same template can be declared as an outer script as well.

    @(Html.DevExtreme().List()
        // ...
        .ItemTemplate("#listItemTemplate")
    )
    
    
    <script id="listItemTemplate" type="text/html">
        <div><%= ProductName %></div>
    </script>

    Simple templates can also be used to nest one widget in another. For example, the following code nests the DataGrid widget in the Popup widget.

    // Configures the "Popup" widget
    @(Html.DevExtreme().Popup()
        // ...
        // Specifies the contents of the "Popup" widget
        .ContentTemplate(@<text>
            // Configures the **DataGrid** widget
            @(Html.DevExtreme().DataGrid()
                .DataSource(d => d.WebApi().Controller("GridData"))
                .Columns(columns => {
                    columns.Add().DataField("DataField1");
                    columns.Add().DataField("DataField2");
                    columns.Add().DataField("DataField3");
                    columns.Add().DataField("DataField4");
                })
            )
        </text>)
    )
  • Heavily nested templates
    Heavily nested templates should be configured in a different manner. For example, consider that you have the Popup widget with the List widget nested in it using a template. List, in its turn, contains another template for its items. In this instance, you need to declare the nested widget (List in this example) in an external code block using the @helper syntax.

    @(Html.DevExtreme().Popup()
        // ...
        .ContentTemplate(@<text>
            @InnerList()
        </text>)
    )
    
    
    @helper InnerList() {
        @(Html.DevExtreme().List()
            // ...
            .ItemTemplate(@<text>
                <div><%= ProductName %></div>
                <div><%= UnitPrice %></div>
            </text>)
        )
    }

Within any template, you can access template-specific free variables that provide supplementary data. For an exhaustive list of them, refer to the description of a specific template in the Reference section.

Another common use case of templates is the detail section of the master-detail UI in the DataGrid widget. Consider the following code, in which the detail section nests another DataGrid whose controller gets the data.OrderID free variable as a loading parameter.

@(Html.DevExtreme().DataGrid()
    .DataSource(d => d.WebApi().Controller("GridData").Key("OrderID"))
    .Columns(columns => {
        columns.Add().DataField("CustomerID");
        columns.Add().DataField("OrderDate");
        // ...
    })
    // Configures the master-detail UI
    .MasterDetail(md => md
        .Enabled(true)
        // Specifies the contents of the detail section
        .Template(@<text>
            @(Html.DevExtreme().DataGrid()
                .DataSource(d => d.WebApi()
                    .Controller("GridData")
                    .LoadAction("OrderDetails")
                    // Passes "OrderID" as a parameter to "GridDataController"
                    .LoadParams(new { orderID = new JS("data.OrderID") })
                )
            )
        </text>)
    )
)

Note that the data.OrderID free variable is wrapped in the new JS() construction. This construction allows you to embed JavaScript statements in the resulting widget configuration. In particular, the data source configuration of the nested DataGrid from the preceding code yields the following output.

"dataSource": {
    "store": DevExpress.data.AspNet.createStore({
        "loadParams": {
            "orderID": data.OrderID
        },
        "loadUrl": "/api/GridData/OrderDetails",
        "insertUrl": "/api/GridData/Post",
        "updateUrl": "/api/GridData/Put",
        "deleteUrl": "/api/GridData/Delete"
    })
}

You can find more examples of templates in our sample application.