The jquery TOOLS library has a nice API for creating HTML5 range inputs in older browsers. And the MVC 2 framework for ASP.NET offers a nice way of creating interactive web applications for Windows servers. The logical thing to do, then, is combine them somehow.
First, we'll create a custom .NET attribute called StepSize
that we can attach to a model property. This attribute will be used to determine the step
attribute of our range input. We'll use the existing .NET Range property attribute to determine the min
and max
values of our range input.
Next, we need some HtmlHelper extension methods to create the range input on our views. We'll create a strongly-typed version of this method and use reflection to traverse the model's property for which we're building the range input. These methods return an MvcHtmlString
which means all the contents have been encoded and are ready to be displayed.
Once all that compiles, we can simply write the following line in our view to get a nice range input (which can be styled with CSS.)
<%= Html.RangeInputFor(model => model.SomeProperty) %>
Of course, you'll need to make sure your jquery TOOLS functions are set up correctly. I'm just using this simple call in my $(document).ready()
function:
$(":range").rangeinput();
As always, check the code before you use it. I don't guarantee that these methods won't allow Satan himself to spawn in your web page and ruin the internet.

namespace YourNamespace
{
[AttributeUsage(
AttributeTargets.Property,
AllowMultiple = false
)]
public class StepSizeAttribute : Attribute
{
public object StepSize { get; private set; }
private StepSizeAttribute(object stepSize)
{
this.StepSize = stepSize;
}
public StepSizeAttribute(int stepSize)
: this((object)stepSize) { }
public StepSizeAttribute(double stepSize)
: this((object)stepSize) { }
public StepSizeAttribute(float stepSize)
: this((object)stepSize) { }
public StepSizeAttribute(decimal stepSize)
: this((object)stepSize) { }
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Web.Mvc;
using System.ComponentModel.DataAnnotations;
namespace YourNamespace
{
public static partial class HtmlHelperExt
{
public static MvcHtmlString RangeInput(this HtmlHelper htmlHelper,
string name, double min, double max, double value, double step, object htmlAttributes)
{
var range = new TagBuilder("input");
range.Attributes.Add("type", "range");
range.Attributes.Add("min", htmlHelper.Encode(min));
range.Attributes.Add("max", htmlHelper.Encode(max));
range.Attributes.Add("value", htmlHelper.Encode(value));
range.Attributes.Add("step", htmlHelper.Encode(step));
range.Attributes.Add("id", htmlHelper.Encode(name));
range.Attributes.Add("name", htmlHelper.Encode(name));
if (htmlAttributes != null)
range.MergeAttributes((IDictionary<string, object>)htmlAttributes, true);
return MvcHtmlString.Create(range.ToString(TagRenderMode.SelfClosing));
}
public static MvcHtmlString RangeInputFor<TModel,
TProperty>(this HtmlHelper<TModel> htmlHelper,
Expression<Func<TModel, TProperty>> expression)
where TModel : class
{
return RangeInputFor(htmlHelper, expression, null);
}
public static MvcHtmlString RangeInputFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper,
Expression<Func<TModel, TProperty>> expression, object htmlAttributes)
where TModel : class
{
var mexp = expression.Body as MemberExpression;
var range = mexp.Member.GetCustomAttributes(typeof(RangeAttribute), false)
.OfType<RangeAttribute>().FirstOrDefault();
if (range == null)
throw new ArgumentException("The property " +
mexp.Member.Name + " does not have a range attribute.");
var min = 0m;
var max = 0m;
if (!Decimal.TryParse(range.Minimum.ToString(), out min))
throw new InvalidCastException("The minimum value of the
range attribute (" + range.Minimum.ToString() + ") for " +
mexp.Member.Name + " cannot be converted to numeric.");
if (!Decimal.TryParse(range.Maximum.ToString(), out max))
throw new InvalidCastException("The maximum value
of the range attribute (" + range.Maximum.ToString() + ")
for " + mexp.Member.Name + " cannot be converted to numeric.");
var value = 0m;
var strValue = typeof(TModel).GetProperty(mexp.Member.Name).GetValue
(htmlHelper.ViewData.Model, null).ToString();
if (!Decimal.TryParse(strValue, out value))
throw new InvalidCastException("The value of " +
mexp.Member.Name + " cannot be converted to numeric.");
var step = 1m;
var stepSize = mexp.Member.GetCustomAttributes(typeof(StepSizeAttribute), false)
.OfType<StepSizeAttribute>().FirstOrDefault();
if (stepSize != null)
if (!Decimal.TryParse(stepSize.StepSize.ToString(), out step))
throw new InvalidCastException("The value of the step size
(" + stepSize.StepSize.ToString() + ")
cannot be converted to numeric.");
var rangeInput = htmlHelper.RangeInput(
mexp.Member.Name,
(double)min,
(double)max,
(double)value,
(double)step,
htmlAttributes
);
return rangeInput;
}
}
}
CodeProject