CheckBox Issue with MVC 3 WebGrid Paging & Sorting

March 19, 2012 at 8:52 PMWebsite Sorcery

I've encountered an issue with a CheckBox on a page along with the MVC 3 Web Grid. The issue occurs while paging and sorting, giving the following error:

The parameter conversion from type 'System.String' to type 'System.Boolean' failed. See the inner exception for more information.

Investigating the error further it seems the InnerException is:

{"true,false is not a valid value for Boolean."}

It took me a while to find a workable solution and I spent far too long searching on Google for any help on the matter. Fortunately I managed to get it working, and later on in this post I'll give you the answer. Firstly I'll discuss why it occurs.

An Html CheckBox will only post back a value when it is checked, and is ignored when false. This functionality is by design, for good or bad. To compensate for this, a hidden field is created with the same name, and this will post back either true or false. This will give the resulting QueryString:

Unchecked = false.

Checked = true,false.

Slightly odd, but that's the way it is. Let's look at some code.

View Code (cshtml):

@Html.CheckBox("MyBoolValue", @Model.MyBoolValue)

Controller Code:

bool myBoolValue = true;

if (Request.QueryString["MyBoolValue"] != null)
{
     myBoolValue = Request.QueryString["MyBoolValue"].Contains("true");
}

What this means is that a value of true,false will be set to true, or otherwise false.

I'd like to state a few more things in case the above doesn't work for you, and in reality my code was slightly different. I separated the name of the CheckBox completely from the value of the model, so my @Model.MyBoolValue was bound to a CheckBox called BoolValue which is what I read back from the query string. In my Controller method I do not use MVC binding, instead using the QueryString to read the value. The issue occurs with the MVC binding which is why I opted to sidestep it completely.

Another option is to create the CheckBox without the Html.CheckBox helper, coding it like so:

<input type="CheckBox" name="MyBoolValue" value="@Model.MyBoolValue"/>

Or you could go a step further and use Custom Model Binding.

Posted in: .NET Development | ASP.NET MVC | Razor

Tags: ,

ASP.NET MVC WebGrid - Problems Sorting Columns Bound to Dictionary / Enumeration Values

March 16, 2012 at 5:29 AMWebsite Sorcery

I have a WebGrid bound to a List of Dictionary values, with which I dynamically create columns for each Key/Value attribute. I set a default sort (defaultSort) to the first attribute in the Dictionary, and find this sorts perfectly within the WebGrid with ASC/DESC appearing correctly in the query string. The problem I seemed to have was none of the other columns sorted correctly, retaining the sort order of Ascending (ASC).

I did some research and found this is also an issue when binding to Enumeration (enum) values, and imagine it to be the case when binding to other collections too.

I found a fairly tidy way of fixing the issue, and that was to set the Grid.SortColumn on the WebGrid to the last sorted column in the query string. This can be done with little modifications to the Controller and the View.

Controller code:

ViewBag.LastSortedColumn = Request["sort"];

View (cshtml) code:

var grid = new WebGrid();

/* Create & Bind the WebGrid */

grid.SortColumn = (string)ViewBag.LastSortedColumn

What this code does it retain knowledge of the last sorted column, which is necessary as the WebGrid loses track of the last sorted column when it's not bound to a definitive property.

If this has helped you, then please take the time to click the Google+ and Share buttons. Thank you.

Posted in: .NET Development | ASP.NET MVC | Razor

Tags:

Alternating Row Style with the ASP.NET MVC MvcContrib Grid

March 14, 2012 at 4:01 AMWebsite Sorcery

I will assume from your arrival on this particular page that you're attempting to create an Alternating Row / Zebra style on your MvcContrib Grid? You've come to the right place!

The MvcContrib Grid uses default styles, such as grid for the table, gridrow for a standard table row, and gridrow_alternate for alternating table rows. This means you can create your zebra style with the following CSS:

.gridrow
{
    background-color: Yellow;
}

.gridrow_alternate
{
    background-color: Red;
}

All I can say is, if you like the red and yellow color scheme then please take the time to like this page ;o)

Posted in: ASP.NET MVC | CSS

Tags: ,

Setting the ASP.NET MVC WebGrid Table Header Background Color

March 13, 2012 at 4:06 AMWebsite Sorcery

I was attempting to style a WebGrid and ran into difficulties setting the background color of the table header. Take the following css for example:

.webgrid-header
{
    background-color: Red;
}

Would this set the header background to Red? No-siree! What you need to do is specify a th tag for the webgrid-header, like so:

.webgrid-header th
{
    background-color: Red;
}

Bob's your uncle!

For more information on styling the ASP.NET MVC WebGrid have a look at this post.

Posted in: ASP.NET MVC

Tags:

Styling the ASP.NET MVC WebGrid

March 12, 2012 at 10:26 PMWebsite Sorcery

As great as the ASP.NET MVC WebGrid is, it's very bland out of the box. Fortunately it's easy to style and this doesn't require much explanation. In two minutes flat you can have your WebGrid looking something like this:

ASP.NET MVC WebGrid Css Styling

Here's some starter code:

@grid.GetHtml(
        
            ...
        
        tableStyle: "webgrid",
        headerStyle: "webgrid-header",
        footerStyle: "webgrid-footer",
        alternatingRowStyle: "webgrid-alternating-row",
        selectedRowStyle: "webgrid-selected-row",
        rowStyle: "webgrid-row-style"
    )

Create a WebGrid.css style sheet and ensure you reference it from your _Layout.cshtml (or add the relevant styles to your Site.css if you prefer). Use the following as a start point which gives you the look and feel in the image above:

.webgrid
{
    width: 100%;
    margin: 0px;
    padding: 0px;
    border: 0px;
    border-collapse: collapse;
}

.webgrid a
{
    color: #000;
}

.webgrid-header
{
    padding: 0px 5px;
    text-align: center;
    border-bottom: 2px solid #739ace;
    height: 20px;
    border-top: 2px solid #D6E8FF;
    border-left: 2px solid #D6E8FF;
    border-right: 2px solid #D6E8FF;
}

.webgrid-header th
{
    background-color: #eaf0ff;
    border-right: 1px solid #ddd;
}

.webgrid-footer
{
    padding: 6px 5px;
    text-align: center;
    background-color: #e8eef4;
    border-top: 2px solid #3966A2;
    height: 25px;
    border-bottom: 2px solid #D6E8FF;
    border-left: 2px solid #D6E8FF;
    border-right: 2px solid #D6E8FF;
}

.webgrid-alternating-row
{
    height: 22px;
    background-color: #f2f2f2;
    border-bottom: 1px solid #d2d2d2;
    border-left: 2px solid #D6E8FF;
    border-right: 2px solid #D6E8FF;
}

.webgrid-row-style
{
    height: 22px;
    border-bottom: 1px solid #d2d2d2;
    border-left: 2px solid #D6E8FF;
    border-right: 2px solid #D6E8FF;
}

.webgrid-selected-row
{
    font-weight: bold;
}

Enjoy!

Posted in: ASP.NET MVC

Tags: ,

A Strongly Typed ASP.NET MVC WebGrid

March 12, 2012 at 9:58 PMWebsite Sorcery

I've been working on a project which requires server side paging and sorting to cope with potentially millions of records. I originally used the jQuery Tablesorter plugin with client side sorting and paging which worked well both functionally and aesthetically, but for the full bells and whistles project I stumbled upon the MSDN post Get the Most out of WebGrid in ASP.NET by Stuart Leeks.

Within in the midst of Stuart's post he creates a wrapper for the ASP.NET MVC WebGrid to allow Strong Typing. I debated the practicality of using strong typing with WebGrid which could be said to work better dynamically, but there are other benefits to strong typing which make this a decent little coding nugget.

Before getting to the code I'll give you a quick looky at how it works from the UI:

<div>
    @{
        var grid = new WebGrid<Product>(null, rowsPerPage: Model.PageSize, defaultSort: "Name");
        grid.Bind(Model.Products, rowCount: Model.TotalRows, autoSortAndPage: false);
    }
    @grid.GetHtml(
        columns: grid.Columns(
            grid.Column(
                "Name", format: @<text>@Html.ActionLink((string)item.Name,
                "Details", "Products", new { id = item.Id }, null)</text>),
            grid.Column("Description")
        )
    )
</div>

I created the WebGrid wrapper class in an Infrastructure folder in my website. It references another class called EnumerableExtensions which provides a useful SafeCast method to cast an IEnumerable. Here's the code:

Strongly Typed WebGrid Wrapper (WebGrid.cs)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Helpers;

namespace MyWebSite.Infrastructure
{
    /// <summary>
    /// Wrapper for System.Web.Helpers.WebGrid that preserves the item type from the data source
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public class WebGrid<T> : WebGrid
    {
        /// <param name="source">Data source</param>
        /// <param name="columnNames">Data source column names. Auto-populated by default.</param>
        /// <param name="defaultSort">Default sort column.</param>
        /// <param name="rowsPerPage">Number of rows per page.</param>
        /// <param name="canPage">true to enable paging</param>
        /// <param name="canSort">true to enable sorting</param>
        /// <param name="ajaxUpdateContainerId">ID for the grid's container element. This enables AJAX support.</param>
        /// <param name="ajaxUpdateCallback">Callback function for the AJAX functionality once the update is complete</param>
        /// <param name="fieldNamePrefix">Prefix for query string fields to support multiple grids.</param>
        /// <param name="pageFieldName">Query string field name for page number.</param>
        /// <param name="selectionFieldName">Query string field name for selected row number.</param>
        /// <param name="sortFieldName">Query string field name for sort column.</param>
        /// <param name="sortDirectionFieldName">Query string field name for sort direction.</param>
        public WebGrid(IEnumerable<T> source = null, IEnumerable<string> columnNames = null, string defaultSort = null, int rowsPerPage = 10, bool canPage = true, bool canSort = true, string ajaxUpdateContainerId = null, string ajaxUpdateCallback = null, string fieldNamePrefix = null, string pageFieldName = null, string selectionFieldName = null, string sortFieldName = null, string sortDirectionFieldName = null)
            : base(source.SafeCast<object>(), columnNames, defaultSort, rowsPerPage, canPage, canSort, ajaxUpdateContainerId, ajaxUpdateCallback, fieldNamePrefix, pageFieldName, selectionFieldName, sortFieldName, sortDirectionFieldName)
        {
        }
        public WebGridColumn Column(string columnName = null, string header = null, Func<T, object> format = null, string style = null, bool canSort = true)
        {
            Func<dynamic, object> wrappedFormat = null;
            if (format != null)
            {
                wrappedFormat = o => format((T)o.Value);
            }
            WebGridColumn column = base.Column(columnName, header, wrappedFormat, style, canSort);
            return column;
        }
        public WebGrid<T> Bind(IEnumerable<T> source, IEnumerable<string> columnNames = null, bool autoSortAndPage = true, int rowCount = -1)
        {
            base.Bind(source.SafeCast<object>(), columnNames, autoSortAndPage, rowCount);
            return this;
        }
    }
}

Enumberable Extensions (Enumerable Extensions.cs)

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;

namespace MyWebSite.Infrastructure
{
    public static class EnumerableExtensions
    {
        public static IEnumerable<TTarget> SafeCast<TTarget>(this IEnumerable source)
        {
            return source == null ? null : source.Cast<TTarget>();
        }
    }
}

To read more about the WebGrid I suggest reading Stuart Leeks' excellent post. Additionally, learn how to Style the ASP.NET MVC WebGrid.

Posted in: ASP.NET MVC

Tags: ,

Using conditional statements in an MVC 3 WebGrid column using Razor

March 8, 2012 at 3:01 AMWebsite Sorcery

You may have a requirement to create conditional statements within an MVC 3 WebGrid control. For example, you may have a column which displays a hyperlink if the user is an Administrator, or plain text to standard users. Perhaps you want green text for an item which is valid, or red if not? There are many situations where you want to render a grid cell based on a condition, and the possibilities are endless.

So how can you do this using the MVC 3 WebGrid Control? The solution, fortunately, is easy peasy.

Here's how:

 

@grid.GetHtml(
  columns: grid.Columns(
    grid.Column("Conditional Cell Sample", format: @<text>@if(true) { @Html.ActionLink("Go here", "Home") } else { @Html.ActionLink("Or here", "Away") }</text>))
)

 

Simply replace the @if(true) statement with your conditional logic, and define the two conditions as required.

What if you want a switch statement? You can do that too. You have to love the simplicity of Razor!

Posted in: .NET Development | ASP.NET MVC

Tags:

Theme Chrome - A Nice jQuery UI Example

March 8, 2012 at 2:15 AMWebsite Sorcery

ThemeChrome.net is a site that allows a non-technical Chrome user to create a pretty theme for their browser. Normally, the process of creating a Google Chrome theme (CRX file) is a bit time consuming - you need to create a manifest file in json, specify all the images, and figure out what properties affect which part of the browser window. That's fine if you're a geek and like fiddling with such things, but what if you're not? This site makes it easy peasy. 

Theme Google Chrome

 

Anyway, I shall digress as the purpose of this blog post isn't to discuss Google Chrome or how to theme it. That stuff can be found elsewhere on the web. I've been creating a number of MVC websites recently which has meant being exposed to the capabilities of jQuery UI. I have to say I'm impressed with the bang for buck and ease of implementation. The jQuery UI Theme Roller is a great little tool to play around with different styles, and from there you can export the relevant components.

The ThemeChrome.net theme editor is a great example of jQuery UI in use in the real world, so make sure you have a gander if you're looking for ideas.

Posted in: ASP.NET MVC | jQuery

Tags:

ASP.NET C# / MVC - Export an HTML Table to Excel/CSV

March 7, 2012 at 3:03 AMWebsite Sorcery

Simple stuff. Simply replace output with your table:

Response.ContentType = "application/force-download";
Response.AddHeader("content-disposition", "attachment; filename=output.xls");
Response.Write("<html xmlns:x=\"urn:schemas-microsoft-com:office:excel\">");
Response.Write("<head>");
Response.Write("<META http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\">");
Response.Write("<!--[if gte mso 9]><xml>");
Response.Write("<x:ExcelWorkbook>");
Response.Write("<x:ExcelWorksheets>");
Response.Write("<x:ExcelWorksheet>");
Response.Write("<x:Name>Report Data</x:Name>");
Response.Write("<x:WorksheetOptions>");
Response.Write("<x:Print>");
Response.Write("<x:ValidPrinterInfo/>");
Response.Write("</x:Print>");
Response.Write("</x:WorksheetOptions>");
Response.Write("</x:ExcelWorksheet>");
Response.Write("</x:ExcelWorksheets>");
Response.Write("</x:ExcelWorkbook>");
Response.Write("</xml>");
Response.Write("<![endif]--> ");
Response.Write(output);
Response.Write("</head>");
Response.Flush();

A more advanced method for creation an ExcelResult:ActionResult and extending the MVC Controller can be found here:

http://stephenwalther.com/blog/archive/2008/06/16/asp-net-mvc-tip-2-create-a-custom-action-result-that-returns-microsoft-excel-documents.aspx

Posted in: .NET Development | ASP.NET MVC

Tags:

Html.ImageActionLink Custom Helper for MVC

February 16, 2012 at 2:58 AMWebsite Sorcery

A lot of people override the Ajax helper to create an Ajax.ImageActionLink. This is fine but in some instances it's easier to use an Html.ImageActionLink.

For example, I had a requirement to return a file in a response stream - something that isn't possible with the Ajax method.

The code is fairly simple, and easy to customize to your requirements:

public static MvcHtmlString ImageActionLink(this HtmlHelper helper, string imagePath, 
  string actionName, string controllerName, object routeValues, object imageAttributes, 
  object linkAttributes)
{
var urlHelper = new UrlHelper(helper.ViewContext.RequestContext, 
    helper.RouteCollection);

var aBuilder = new TagBuilder("a");
aBuilder.MergeAttributes(new RouteValueDictionary(linkAttributes));
aBuilder.MergeAttribute("href", urlHelper.Action(actionName, controllerName, 
    routeValues));

var imgBuilder = new TagBuilder("img");
imgBuilder.MergeAttributes(new RouteValueDictionary(imageAttributes));
imgBuilder.MergeAttribute("src", imagePath);

aBuilder.InnerHtml = imgBuilder.ToString(TagRenderMode.SelfClosing);

return new MvcHtmlString(aBuilder.ToString(TagRenderMode.Normal));
}

Posted in: .NET Development | ASP.NET MVC

Tags: