Theming 

In the Mvc Controls Toolkit the various parts of a complex controls like a grid such as pager, filtering and sorting  facilities, are not rendered in a predefined arrangement, but as separate parts to leave to the developer the maximum control over generated Html . However, in order to enhance re-usability of code we allow the definition of predefined arrangements together with their graphic styles with the help of Themes. Themes specify both Css settings, Standard Templates, and Helpers Options. A Theme is composed of a Css file and possible images, plus a folder containing various PartialViews. The Css file may have any name and there is no constraint on its location. Each Css file just defines the Css classes used by all Partial Views in the corresponding Theme folder. The current release includes just a couple of themed controls as example, one for the DualSelectBox and the other for the DataGrid. Complete Themes will be provided with separate distributions, and each user can build its own custom Themes by using the examples included as a guideline. 

The Theme Name is just the name of the folder containing all Partial Views. All Theme folders are placed under a folder named Themes that is in the Shared folder of the main Views folder. Therefore if we have a Theme named Test the folder tree  is:

In the example above the Theme folder named Test contains just a Partial view but normally,  a theme should contain several Partial Views. Theme developers are encouraged to use a similar structure for the Css files, too:

There is not a one to one mapping between Partial Views and Helpers, for instance,  there might be several Partial Views that specifies different templates, options and Css classes for a DataGrid, according to the different Roles that a datagrid may have in the Theme. In fact since most of the Controls in the Mvc Controls Toolkit are templated they can fulfill different roles: a datagrid can be used do display a standard table, but can be used also to display the posts of a blog! Clearly the same Theme may contain both of the previous roles, therefore the same control can be rendered in different way in the same Theme.

Accordingly, a themed control is is specified by means of two identifiers: the Theme Name, plus a further Name that identifies its role in the Theme. This two identifiers are called respectively: Theme and Name. As already hinted the Theme corresponds to the theme folder name, while the Name corresponds to the name of the Partial View. Thus, in the tree folder above we have a "DataGrid" Name in the "Test" Theme

There is a standard way to invoke Themed DataGrid, Themed SortableList, Themed Pagers,  Themed CheckBoxList, and Themed DualSelectBox, as summarized by the table below:

DataGrid ThemedDataGridFor
SortableList ThemedSortableListFor
PagerFor ThemedPagerFor
Pager ThemedPager
CheckBoxList ThemedChoiceListFor
DualSelectBox ThemedChoiceListFor

As you can see both the CheckBoxList and the DualselectBox are associated with the same Themed Helper, because they  fulfill substantially the same role, that is:  enabling the user to perform a multi-selection. When you call the ThemedChoiceListFor the choice between the DualSelectBox and the CheckBoxList is performed by the Partial View that implements a specific Name of a Theme.  

The TreeView has no standard helper associated with it, because the roles it can fulfill are very different. The Theme developer has full freedom in defining Themed Helpers based on it.

All other controls are simple enough to be Themed just with the help of the Css file associated with the Theme. However the Theme developer has the freedom to define Themed Helpers based on them.

The Css classes used in a theme must have the structure: Theme-<name>-<function>. Where "Theme" is a fixed keyword, "name" is the name part of theTheme-Name pair. 

For instance, if we would like a TypedTextBox be themed according to the currently selected theme we have to call its watermark class: Theme-TypedTextBox-Watermark.  Since each Theme is supposed to have a definition for this class, the watermark of our typed textbox will be automatically themed. Some themes may also define Css classes for specialized versions of the TypedTextBox, that in that case will have a "name" that is different from "TypedTextBox", such as: Theme-SearchTypedTextBox-Watermark

Also the Css classes used by the Partial Views of the themes must have the same structure. For instance, the style of the header of a DataGrid have the name: Theme-DataGrid-Header.

While the whole  graphics of a Theme is defined in the Theme itself, strings used in buttons, etc. cannot be defined once and for all by the Theme designer. The user can provide names for all such strings by declaring a resource dictionary.  The resource dictionary is declared by assigning its type to the static variable ResourceType of the ThemedControlsStrings class. The resource dictionary may also be passed as argument to the MVCControlsToolkit.Core.Extensions.Register method that initialize the Mvc Controls Toolkit in the Global.asax:

 

MVCControlsToolkit.Core.Extensions.Register(MyResourceDictionaryType);

 

The keys that Can be defined are:

Pager: Page_Next Page_Prev Page_First Page_Last

DualSelect: DualSelect_MoveLeft DualSelect_MoveRight DualSelect_MoveAllLeft DualSelect_MoveAllRight DualSelect_MoveUp DualSelect_MoveDown

ItemsControls: Item_Insert Item_Delete Item_Undelete Item_Edit Item_ResetRow Item_UndoChange Item_Deleted

All the above but Item_Deleted  define strings to be used by buttons. Item-Deleted is the strings to be used in the deletedItemTemplate of the DataGrid (something like "deleted Row").

If the user either doesn't provide a resource dictionary or doesn't provide a key, a default is used.

If the user would like to give a different string to a property of a specific Name in a Theme it can add a key whose name is obtained by postfixing the original key that defines that property with _<Name> . For instance Item_Edit_CommentsDataGrid. Where, the Name CommentsDataGrid identifies a DataGrid specialized for rendering comments in a Blog. 

Theme developers can get the string associated to a key by calling the static method of the class ThemedControlsStrings:

 

public static string Get(string key, string name)

 

where name is for the Name associated to the PartialView(DataGrid, CommentsDataGrid, etc.). The above call resolve the key, possibly returning just its default value. The current Theme is set with the SetTheme static method of the ThemedControlsString static class:

 

ThemedControlsStrings.SetTheme("Test", false);

 

The second parameter is optional and if set to true forces the theme to be stored in a permanent cookie. So, further calls to the GetTheme method will return the chosen theme with no need to call again the SetTheme method.

While it can be retrieved with the GetTheme method:

 

ThemedControlsStrings.GetTheme();

 

 

A default theme can be set,  by passing it as second argument of the the MVCControlsToolkit.Core.Extensions.Register method that initialize the Mvc Controls Toolkit in the Global.asax:

 

public static void Register(Type themedControlsResources=null, string defaultTheme="Standard")

 

 

ThemedChoiceListFor

The ThemedChoiceListFor accepts as arguments tthe first two arguments of the CheckBoxFor Helper, plus an optional name argument, that is the name of the Partial View that implements it in the Theme:

 

    public static MvcHtmlString ThemedChoiceListFor<TModel, TChoiceItem, TValue, TDisplay>
            (
           this HtmlHelper<TModel> htmlHelper,
           Expression<Func<TModel, IEnumerable<TValue>>> expression,
           ChoiceList<TChoiceItem, TValue, TDisplay> choiceList,
           string name="ChoiceList")
            where TValue : IComparable, IConvertible

 

 

below an example of its use:

 

@Html.ThemedChoiceListFor(m => m.Roles,new ChoiceList<RoleInBlog, int, string>(
                                RegisterModel.AllRoles,
                                (t => t.Code),
                                (t => t.Name)),
                                "Dualselect") %>

 

 

In the example above the optional name argument requires the use of an implementation based on the DualselectBox, that is shown below:

 

@{ var options = ViewData["ThemeParams"] as ChoiceListDescription;
   var RoleSelect = DualSelectHelper.DualSelectFor(options.HtmlHelper, options.Expression, options.ChoiceList);
   
    }

<table>
               
    <tr>
    <td  valign="middle" align="center">
    @RoleSelect.AvailableItems(
        new Dictionary<string, object>
        {
            {"style", "height:150px; width: 100px;"}
        }
        ) 
    </td>
    <td valign="middle" align="center"> 
    <table>
        <tr><td  valign="middle" align="center">
        @RoleSelect.ClearSelectionButton(ThemedControlsStrings.Get("DualSelect_MoveAllLeft", "DualSelect"))
        </td>
        </tr>
        <tr><td  valign="middle" align="center">
        @RoleSelect.UnSelectButton(ThemedControlsStrings.Get("DualSelect_MoveLeft", "DualSelect"))
        </td>
        </tr>
        <tr><td  valign="middle" align="center">
        @:RoleSelect.SelectButton(ThemedControlsStrings.Get("DualSelect_MoveRight", "DualSelect"))
        </td>
        </tr>
        <tr><td  valign="middle" align="center">
        @RoleSelect.SelectAllButton(ThemedControlsStrings.Get("DualSelect_MoveAllRight", "DualSelect"))
        </td>
        </tr>
    </table>
    </td>
    <td  valign="middle" align="center">
    @RoleSelect.SelectedItems(
        new Dictionary<string, object>
        {
            {"style", "height:150px; width: 100px;"}
        }
        ) 
    </td>
    <td  valign="middle" align="center">
    <div>@RoleSelect.GoUpButton(ThemedControlsStrings.Get("DualSelect_MoveUp", "DualSelect"))</div>
    <div>@RoleSelect.GoDownButton(ThemedControlsStrings.Get("DualSelect_MoveDown", "DualSelect"))</div>
    </td>
</tr>
</table>

 

 

The above code is included in the binary distribution of the library. As you can see the partial view is not strongly types since it must be able to accept any kind of data. The ViewModel passed to the view is the view model of the calling View. A ChoiceListDescription class containing all arguments passed to the ThemedChoiceListFor helper is passed in the ViewData using the ThemeParams key:

 

public class ChoiceListDescription
    {
        public dynamic  Expression{get; set;}
        public dynamic  ChoiceList{get; set;}
        public dynamic HtmlHelper { get; set; }
    }

 

All Properties are dynamic, and among them there is also the helper that must be used to render the Themed Control. As you can see in the implementation we can not use the HtmlHelper as usual, since extension methods are not allowed when using dynamic arguments, therefore we have to call all extension methods as if they were normal static methods.

ThemedPager and ThemedPagerFor

 

public static MvcHtmlString ThemedPagerFor<VM>(
            this HtmlHelper<VM> htmlHelper,
            Expression<Func<VM, int>> page,
            Expression<Func<VM, int>> prevPage = null,
            Expression<Func<VM, int>> totalPages = null,
            string name = "SubmitPager"
            )

It passes to the Partial View of the theme the class:

 

public class SubmitPagerDescription
    {
        public dynamic Page { get; set; }
        public dynamic PrevPage { get; set; }
        public dynamic TotalPages { get; set; }
        public dynamic HtmlHelper { get; set; }
    }

 

public static MvcHtmlString ThemedPager<VM>(
           this HtmlHelper<VM> htmlHelper, 
           int currPage,
           string parameterName,
           string actionName,
           int? totPages = null,
           string targetIdName = "",
           string controllerName = null,
           object otherParameters = null,
           string routeName = null,
           string protocol = null,
           string hostname = null,
           string fragment = null,
           string name = "GetPager")

It passes to the Partial View of the Theme the class:

 

public class LinkPagerDescription
    {
           public int CurrPage { get; set; }
           public string ParameterName { get; set; } 
           public string ActionName { get; set; }
           public dynamic HtmlHelper { get; set; }
           public int? TotPages { get; set; }
           public string TargetIdName { get; set; }
           public string ControllerName { get; set; }
           public object OtherParameters { get; set; }
           public string RouteName { get; set; }
           public string Protocol { get; set; }
           public string Hostname { get; set; }
           public string Fragment { get; set; }
    }

 

 

ThemedDataGridFor and ThemedSortableListFor

The Themed helpers for the Datagrid and for the Sortable List are quite sofisticated, and allow the user to specify, paging, sorting, filtering, and if mouse dragging sorting is enabled. Then, for each columns they allow the user to specify both an edit and a display templates. If the template is supplied as a string,  a Partial View with that name is searched in the Theme folder.  if no template is specified DisplayFor and EditorFor are used. Finally for each column one can specify if sorting or filtering are allowed for that column:

 

        public static MvcHtmlString ThemedDataGridFor<M, TItem>(
            this HtmlHelper<M> htmlHelper,
            Expression<Func<M, List<Tracker<TItem>>>> expression,
            GridFeatures gridFeatures,
            Columns<TItem> fields,
            Expression<Func<M, List<KeyValuePair<LambdaExpression, OrderType>>>> orderExpression = null,
            Expression<Func<M, int>> page=null,
            Expression<Func<M, int>> prevPage=null,
            Expression<Func<M, int>> pageCount=null,
            Expression<Func<M, Expression<Func<TItem, bool>>>> filter=null,
            string title=null,
            string name = "DataGrid"
            )
            where TItem:class, new() 

 

The arguments of the above helper are the main collection to be rendered, all expressions that define the ViewModel properties involved in paging, sorting, and filtering, a title that some theme implementation might use as header, and two arguments that define the features of the overall DatGrid, and of each column: gridFeatures  and fields.

The GridFeatures Type is a Flag enumerable defined as: 

 

[Flags]
    public enum GridFeatures {None = 0, Edit=1, Display=2, Insert=4, Delete=8, ResetRow=16, UndoEdit=32, InsertOne=64, Paging=128, Sorting=256, Filtering=512}

 

while the columns data structure allows the definition of all properties of the columns by means of its method:

 

public Columns<T> Add<F>
            (Expression<Func<T, F>> field, 
            FieldFeatures features= FieldFeatures.None, 
            object editTemplate=null,
            object displayTemplate=null,
            string overrideName=null)

 

The above method returns the original Columns<T> object it was called on, so it may be called again and again on the result of the previous call. The call allows the definition of the property that is associated to the column, through the expression named field, edit and display templates, a column name to override the column name extracted by DataAnnotations, and a Flag enumeration defined as:

 

[Flags]
    public enum FieldFeatures {None = 0, Sort=1, Filtering=2, Hidden=4}

 

 

When a field is marked as Hidden and it has no editTemplate it is rendered into an Hidden Field. This option is usefull for Record keys, that don't need to appear, but only to be stored in the View. If the editDisplay field of a column marked as Hidden is provided it is used. Typically this is usefull to display Detail links.

Below an example of use of the ThemedDataGrid helper:

 

@Html.ThemedDataGridFor(
            m => m.ToDoList,
            GridFeatures.Display | 
            GridFeatures.Edit |  
            GridFeatures.Delete |
            GridFeatures.Insert | 
            GridFeatures.Paging |
            GridFeatures.UndoEdit | 
            GridFeatures.Sorting,
            new Columns<ToDoView>()
            .Add(m => m.Name, FieldFeatures.Sort)
            .Add(m => m.DueDate, FieldFeatures.Sort,
                _S.H<ToDoView>( 
                @<span>              
                    @item.ValidationMessageFor(m => m.DueDate, "*")
                    @item.DateTimeFor(m => m.DueDate, DateTime.Today).Date()
                </span> 
                ),
                _S.H<ToDoView>( 
                @<span>              
                    @item.ValidationMessageFor(m => m.DueDate, "*")
                    @item.DisplayField(m => m.DueDate)
                </span> 
                ))
             .Add(m => m.Description)
             .Add(m => m.id, FieldFeatures.Hidden,
                displayTemplate: _S.H<ToDoView>( 
                    @<span>  
                        @item.DetailLink(Ajax, "Edit Details", DetailType.Edit, "ToDoSubTasks", "Home",
                            new {id = item.ViewData.Model.id}, null)
                    </span>)),
             m => m.ToDoOrder,
             m => m.CurrPage,
             m => m.PrevPage,
             m => m.TotalPages)

 

Please notice that the HtmlHelper that is passed to each column template is strongly typed with the full record and not just with the column Type, to allow more flexibility in deciding how to render the field.

The ThemedDataGridFor helper pass to the Partial View of the Theme the following class:

 

public class GridDescriptionBase
    {
        public GridFeatures Features { get; set; }
        public List<Column> Fields { get; set; }
    }
    
    public class GridDescription:GridDescriptionBase
    {
        public dynamic ToShow {get; set;}
        public dynamic ToOrder { get; set; }
        public string Title { get; set; }
        public dynamic HtmlHelper { get; set; }
        public dynamic Page { get; set; }
        public dynamic PrevPage { get; set; }
        public dynamic PageCount { get; set; }
        public dynamic Filter { get; set; }

    }

 

Where ToShow contains the expression that define the collection to be rendered.

Below an implementation that is included in the Complete Example in the download page. You can use it as a guideline to write your personalized Themes:

 

@using MVCControlsToolkit.Core;
@using MVCControlsToolkit.Controls;

@{
    var options = ViewData["ThemeParams"] as GridDescription;

    Func<dynamic, HelperResult> editTemplate = null;
    if ((options.Features & GridFeatures.Edit) == GridFeatures.Edit)
    {
        editTemplate = EditItem;
    }
    Func<dynamic, HelperResult> displayTemplate = DisplayItem;
    Func<dynamic, HelperResult> insertTemplate = null;
    if ((options.Features & GridFeatures.Insert) == GridFeatures.Insert)
    {
        insertTemplate = InsertItem;
    }
}
@helper InsertItem(dynamic htmlHelper)
    {
        var options = htmlHelper.ViewData["ThemeParams"] as GridDescription;
    int count = 0;
    foreach (Column column in options.Fields)
    {
        if ((column.Features & FieldFeatures.Hidden) != FieldFeatures.Hidden)
        {
            count++;
        }
    }
    if ((options.Features & GridFeatures.Edit) == GridFeatures.Edit) { count++; }
    <td colspan='@count' class="Theme-DataGrid-Column">
        @DataGridHelpers.ImgDataButton(
            htmlHelper, DataButtonType.Insert, 
            Url.Content("~/Content/themes/test/images/add.jpg"), null)</td>
}
@helper DisplayItem(dynamic htmlHelper)
    {
        var options = htmlHelper.ViewData["ThemeParams"] as GridDescription;
        bool hasCustomField=false;
        foreach (Column column in options.Fields)
        {
            if ((column.Features & FieldFeatures.Hidden) != FieldFeatures.Hidden)
            {
            <td class="Theme-DataGrid-Column">
            @{
                if (column.DispalyTemplate == null)
                {
                      @DisplayExtensions.DisplayFor(htmlHelper, column.Field)
                }
                else
                {
                      @CoreHTMLHelpers.TemplateFor(htmlHelper, column.DispalyTemplate)
                }
             }
            </td>
            }
            else if(column.DispalyTemplate != null){
                hasCustomField = true;
            }
        }
        if ((options.Features & GridFeatures.Edit) == GridFeatures.Edit 
            || hasCustomField
            || (options.Features & GridFeatures.Delete) == GridFeatures.Delete)
        {
        <td>
            <table>
                <tr> 
                    @if ((options.Features & GridFeatures.Edit) == GridFeatures.Edit)
                    {         
                        <td>
                            @DataGridHelpers.ImgDataButton(
                                htmlHelper, DataButtonType.Edit, 
                                Url.Content("~/Content/themes/test/images/edit.jpg"), null)
                        </td>
                    }
                    @if ((options.Features & GridFeatures.Delete) == GridFeatures.Delete)
                    {
                        <td>
                            @DataGridHelpers.ImgDataButton(
                                htmlHelper, DataButtonType.Delete, 
                                Url.Content("~/Content/themes/test/images/delete.jpg"), null)
                        </td>
                    }
                    @if (hasCustomField)
                    {
                        foreach (Column column in options.Fields)
                        {
                            if ((column.Features & FieldFeatures.Hidden) == FieldFeatures.Hidden &&
                                column.DispalyTemplate != null)
                            {
                                <td>
                                    @CoreHTMLHelpers.TemplateFor(htmlHelper, column.DispalyTemplate)
                                </td>
                            }
                        }
                    }
               </tr>
            </table>
        </td>
        }
    

}

@helper EditItem(dynamic htmlHelper)
    {
        var options = htmlHelper.ViewData["ThemeParams"] as GridDescription;

        foreach (Column column in options.Fields)
        {
            if ((column.Features & FieldFeatures.Hidden) != FieldFeatures.Hidden)
            {
            <td class="Theme-DataGrid-Column">
            @{
                if (column.EditTemplate == null)
                {
                      @EditorExtensions.EditorFor(htmlHelper, column.Field)
                }
                else
                {
                    if (column.EditTemplate is string)
                    {
                        string templateName = column.EditTemplate as string;
                        templateName = "Themes/Test/" + templateName;
                        @CoreHTMLHelpers.TemplateFor(htmlHelper, templateName)
                    }
                    else
                    {     
                        @CoreHTMLHelpers.TemplateFor(htmlHelper, column.EditTemplate)
                    }
                }
             }
            </td>
            }
        }
        <td>
            <table>
                <tr>          
                    <td>
                        @DataGridHelpers.ImgDataButton(
                            htmlHelper, 
                            DataButtonType.Cancel, 
                            Url.Content("~/Content/themes/test/images/undo.jpg"), null)
                    </td>
                    @if ((options.Features & GridFeatures.UndoEdit) == GridFeatures.UndoEdit)
                    {
                        <td>
                            @DataGridHelpers.LinkDataButton(
                                htmlHelper, 
                                DataButtonType.ResetRow, 
                                ThemedControlsStrings.Get("Item_ResetRow", "DataGrid"), null)
                        </td>
                    }
                    @foreach (Column column in options.Fields)
                    {
                        if ((column.Features & FieldFeatures.Hidden) == FieldFeatures.Hidden)
                        {
                            if (column.EditTemplate != null)
                            {
                                @CoreHTMLHelpers.TemplateFor(htmlHelper, column.EditTemplate)
                            }
                            else
                            {
                                <td style="width:0px">
                                    @InputExtensions.HiddenFor(htmlHelper, column.Field)
                                </td>
                            }
                        }
                    }
               </tr>
            </table>
        </td>
}

@helper DisplayHeader(dynamic htmlHelper, GridDescription options)
    {
    <tr>
        @{bool hasCustomField=false;}
        @foreach (Column column in options.Fields)
        {
            if ((column.Features & FieldFeatures.Hidden) != FieldFeatures.Hidden)
            {
            <td class="Theme-DataGrid-Header"><strong>
                @if ((column.Features & FieldFeatures.Sort) == FieldFeatures.Sort)
                {
                    @DataGridHelpers.SortButtonForTrackedCollection(
                        htmlHelper, 
                        options.ToShow, 
                        column.Field, 
                        sortButtonStyle: SortButtonStyle.Button)
                }
                else
                {
                    if (column.ColumnHeader != null)
                    {
                        @column.ColumnHeader
                    }
                    else
                    {
                       @DataGridHelpers.ColumnNameForTrackedCollection(
                       htmlHelper, 
                       options.ToShow, 
                       column.Field) 
                    }
                }
            </strong></td>
            }
            else if (column.DispalyTemplate != null)
            {
                hasCustomField = true;
            }
            
        }
        @if ((options.Features & GridFeatures.Edit) == GridFeatures.Edit 
            || hasCustomField
            || (options.Features & GridFeatures.Delete) == GridFeatures.Delete)
        {
            <td class="Theme-DataGrid-Header"></td>
        }
    </tr>
}

<table>
@DisplayHeader(options.HtmlHelper, options)
@DataGridHelpers.DataGridFor(options.HtmlHelper,
    options.ToShow,
    ItemContainerType.tr,
    editTemplate,
    displayTemplate,
    null,
    insertTemplate,
    enableMultipleInsert: (options.Features & GridFeatures.InsertOne) != GridFeatures.InsertOne,
        itemCss: "Theme-DataGrid-ItemCss",
        altItemCss: "Theme-DataGrid-AlternateItemCss")
</table>
@if ((options.Features & GridFeatures.Paging) == GridFeatures.Paging)
{
    <div class="Theme-DataGrid-Pager">
        @{ var pager = PagerHelper.PagerFor(options.HtmlHelper, options.Page, options.PrevPage, options.PageCount);}
        @pager.PageButton(ThemedControlsStrings.Get("Page_First", "DataGrid"), PageButtonType.First, PageButtonStyle.Link)
        @pager.PageButton(ThemedControlsStrings.Get("Page_Prev", "DataGrid"), PageButtonType.Previous, PageButtonStyle.Link)
        @pager.PageChoice(5)
        @pager.PageButton(ThemedControlsStrings.Get("Page_Next", "DataGrid"), PageButtonType.Next, PageButtonStyle.Link)
        @pager.PageButton(ThemedControlsStrings.Get("Page_Last", "DataGrid"), PageButtonType.Last, PageButtonStyle.Link)
    </div>
}

@if (((options.Features & GridFeatures.Sorting) == GridFeatures.Sorting) && options.ToOrder != null)
{
        @DataGridHelpers.EnableSortingFor(
            options.HtmlHelper, options.ToShow, 
            options.ToOrder, "Theme-DataGrid-NormalHeader", 
            "Theme-DataGrid-AscendingHeader", "Theme-DataGrid-DescendingHeader", 
            page: options.Page)
}

The SortableListFor helper is defined as:

 

        public static MvcHtmlString ThemedSortableListFor<M, TItem>(
            this HtmlHelper<M> htmlHelper,
            Expression<Func<M, List<TItem>>> expression,
            SortableListFeatures sortableListFeatures,
            Columns<TItem> fields,
            Expression<Func<M, List<KeyValuePair<LambdaExpression, OrderType>>>> orderExpression = null,
            Expression<Func<M, int>> page = null,
            Expression<Func<M, int>> prevPage = null,
            Expression<Func<M, int>> pageCount = null,
            Expression<Func<M, Expression<Func<TItem, bool>>>> filter = null,
            string title = null,
            string name = "SortableList"
            )
            where TItem : class, new()

 

The SortableListFeatures enumerable is defined as:

 

    [Flags]
    public enum SortableListFeatures {None = 0, Insert=1, Delete=2, InsertOne=4, Paging=8, Sorting=16, MouseDraggingSort=64}

 

The above helper passes to the Partial View of the Theme the following class:

 

public class SortableListDescriptionBase
    {
        public SortableListFeatures Features { get; set; }
        public List<Column> Fields { get; set; }
    }

    public class SortableListDescription : SortableListDescriptionBase
    {
        public dynamic ToShow { get; set; }
        public dynamic ToOrder { get; set; }
        public dynamic HtmlHelper { get; set; }
        public string Title { get; set; }
        public dynamic Page { get; set; }
        public dynamic PrevPage { get; set; }
        public dynamic PageCount { get; set; }
        public dynamic Filter { get; set; }

    }

 


Last edited Jun 22, 2014 at 10:41 AM by frankabbruzzese, version 25

Comments

No comments yet.