How can I have multiple HtmlHelperExtensions in MVC3 - asp.net-mvc

I created one file and added a HtmlHelperExtensions class.
public static class HtmlHelperExtensions {
private const string Nbsp = " ";
private const string SelAttribute = " selected='selected'";
public static MvcHtmlString NbspIfEmpty(this HtmlHelper helper, string value)
{
var str = string.IsNullOrEmpty(value) ? Nbsp : value;
return new MvcHtmlString(str);
}
etc...
Now I would like to add more files with more HtmlHelperExtensions. However when I do this I get an error saying:
Duplicate definition: HtmlHelperExtensions
Is it possible for me to have more than one of these classes?

Just name the class something different. You're not allowed duplicate type names under one namespace.
Here's a good tutorial on creating custom Html helpers: http://www.asp.net/mvc/tutorials/creating-custom-html-helpers-cs.

You could name the class differently as stated by #Andrew Whitaker or you could use the partial keyword.
public static partial class HtmlHelperExtensions
{
// helpers ...
}
public static partial class HtmlHelperExtensions
{
// other helpers ...
}

Related

MVC html helper to generate enum drop down list dynamiclly

My model is:
public class DynamicEnum
{
public string Name {get; set;}
public int Value {get; set;}
}
public class ViewModel
{
public DynamicEnum DynamicEnum {get; set;}
}
Public ActionResult MyAction
{
var model = new ViewModel();
model.DynamicEnum = new DynamicEnum(){ Name = "System.DayOfWeek", Value = 2};
return View(model);
}
So in the view I need a HtmlHelper to dynamically generate DropDownListFor like:
#Html.EnumDropDownListFor(m => m.DynamicEnum)
I used MVC 5.2.3, Does any one have any idea?
One way to achieve this would be to use reflection:
public static class HtmlExtensions
{
public static IHtmlString EnumDropDownListFor<TModel>(
this HtmlHelper<TModel> html,
Expression<Func<TModel, DynamicEnum>> expression)
{
var metadata = ModelMetadata.FromLambdaExpression(expression, html.ViewData);
var dynamicEnum = (DynamicEnum)metadata.Model;
var enumType = Type.GetType(dynamicEnum.Name, true);
if (!enumType.IsEnum)
{
throw new Exception(dynamicEnum.Name + " doesn't represent a valid enum type");
}
// TODO: You definetely want to cache the values here to avoid the expensive
// reflection call: a ConcurrentDictionary<Type, IList<SelectListItem>> could be used
var enumNames = Enum.GetNames(enumType);
var values = enumNames.Select(x => new SelectListItem
{
Text = x,
Value = ((int)Enum.Parse(enumType, x)).ToString(),
}).ToList();
string name = ExpressionHelper.GetExpressionText(expression) + ".Value";
return html.DropDownList(name, values);
}
}
Remark: The HtmlHelper.EnumDropDownListFor extension method already exists in ASP.NET MVC so make sure that you bring the namespace in which you declared your custom extension method into scope to avoid collisions. Or just use a different method name.

static types cannot be used as parameters in htmlhelpers

I created custom HtmlHelper like this:
public static class HtmlHelper
{
public static MvcHtmlString CreateHr(this HtmlHelper helper)
{
return MvcHtmlString.Create("<div class='line'></div>");
}
}
but when I build project I get this Error:
static types cannot be used as parameters
I searched Google, but I can't find similar question.
How can I do this?
Call your class something other than HtmlHelper, like HtmlHelperExtensions.
Not only are you not allowed to have a static class as a method parameter type (because it would make no sense), you would be shadowing the very class you're trying to extend.
Do not name your helper HtmlHelper because this means you try to shadow base HtmlHelper from MVC framework. Instead try:
using System;
using System.Web.Mvc;
namespace MvcApplication1.Helpers
{
public static class HrExtensions
{
public static string CreateHr(this HtmlHelper helper)
{
return MvcHtmlString.Create("<div class='line'></div>");
}
}
}
more details here: http://www.asp.net/mvc/overview/older-versions-1/views/creating-custom-html-helpers-cs

How to write HtmlHelper in Fluent syntax

I have a simple tag builder that looks like this:
public static MvcHtmlString Tag(this HtmlHelper helper, string tag, string content)
{
var tagBuilder = new TagBuilder(tag){InnerHtml = content};
return MvcHtmlString.Create(tagBuilder.ToString(TagRenderMode.NormalTag));
}
And, I can use it like this:
#Html.Tag("em", Model.Title)
which produces:
<em>The Title</em>
How can this be written to use a Fluent Syntax so it's use would look like this:
#Html.Tag("em").Content(Model.Title)
You have to define a builder interface and implementation. I hope my example can provide some guidance:
public static class MyHtmlExtensions
{
public static IMyTagBuilder Tag(this HtmlHelper helper, string tag)
{
return new MyTagBuilder(tag);
}
}
Then you define your builder interface and implementation:
public interface IMyTagBuilder : IHtmlString
{
IHtmlString Content(string content);
}
public class MyTagBuilder : IMyTagBuilder
{
private readonly TagBuilder _tagBuilder;
public MyTagBuilder(string tag)
{
_tagBuilder = new TagBuilder(tag);
}
public IHtmlString Content(string content)
{
_tagBuilder.InnerHtml = content;
return this;
}
public string ToHtmlString()
{
return _tagBuilder.ToString(TagRenderMode.NormalTag);
}
}
Since IMyTagBuilder implements IHtmlString, it can be used either with or without calling .Content() afterwards.
A great trick to use when implementing fluent interfaces it to use a IFluentInterface to hide object members (ToString, Equals, GetHashCode and GetType) from IntelliSense, it removes some noise.
EDIT: A great resource for building fluent APIs is Daniel Cazzulino's screencast from building Funq here

How to sort all dropdownLists by name in ASP.net MVC

Is it possible to automatically sort all dropdownLists in ASP.net MVC project?
I don't want to go one by one and sort them explicitly. Is there a way to do this automatically on all dropdownLists in the project?
Create a HtmlHelperExtensions class that has an extension method that does what you want. Something like this:
public static class HtmlHelperExtensions
{
public static MvcHtmlString SortedDropDownList(this HtmlHelper htmlHelper, string name, IEnumerable<SelectListItem> selectList)
{
return htmlHelper.DropDownList(name, selectList.OrderBy(x => x.Text));
}
}
Whatever namespace you stick the helper in, make sure it's added to configuration\system.web.webPages.razor\pages\namespaces in the web.config found in your \Views folder so that you can use it in your view.
You could create HtmlHelperExtension class as friism sugested, or you could create extension method on SelectList like this:
public static class SortedList
{
public static void SortList(this SelectList selectList, SortDirection direction)
{
//sort content of selectList
}
}
and then use it like this:
var sel = new SelectList(new List<string> {"john", "mary", "peter"});
sel.SortList(SortDirection.Ascending);
Either way, you are going to change every line of code where you want to sort those lists.

How can I use a HTML helper method in an extension method?

I have the following classes:
public class Note
{
public string Text { get; set; }
public RowInfo RowInfo { get; set; }
}
public class RowInfo
{
[DisplayName("Created")]
public DateTime Created { get; set; }
[DisplayName("Modified")]
public DateTime Modified { get; set; }
}
In my view I have the following which creates HTML with the correct name and value:
Html.HiddenFor(model => model.Note.Created)
Now what I am trying to do is to create an extension method that will include the above and that I can call in each view. I have tried doing the following. I think I am on the right track but I don't know how to do the equivalent of "model => model.Note.Created" Can someone give me some advice on how I can do this and what I would need to replace the text inside the parenthesis with. I don't have a model but I can do this some other way so the hidden field will go look at my class to get the correct DisplayName just like it does above?
namespace ST.WebUx.Helpers.Html
{
using System.Web.Mvc;
using System.Web.Mvc.Html
using System.Linq;
public static class StatusExtensions
{
public static MvcHtmlString StatusBox(this HtmlHelper helper, RowInfo RowInfo )
{
return new MvcHtmlString(
"Some things here ... " +
System.Web.Mvc.Html.InputExtensions.Hidden( for created field ) +
System.Web.Mvc.Html.InputExtensions.Hidden( for modified field ) );
}
}
You could write a strongly typed helper taking a λ-expression:
public static class StatusExtensions
{
public static IHtmlString StatusBox<TModel, TProperty>(
this HtmlHelper<TModel> helper,
Expression<Func<TModel, TProperty>> ex
)
{
return new HtmlString(
"Some things here ... " +
helper.HiddenFor(ex));
}
}
and then:
#Html.StatusBox(model => model.RowInfo.Created)
UPDATE:
As requested in the comments section here's a revised version of the helper:
public static class StatusExtensions
{
public static IHtmlString StatusBox<TModel>(
this HtmlHelper<TModel> helper,
Expression<Func<TModel, RowInfo>> ex
)
{
var createdEx =
Expression.Lambda<Func<TModel, DateTime>>(
Expression.Property(ex.Body, "Created"),
ex.Parameters
);
var modifiedEx =
Expression.Lambda<Func<TModel, DateTime>>(
Expression.Property(ex.Body, "Modified"),
ex.Parameters
);
return new HtmlString(
"Some things here ..." +
helper.HiddenFor(createdEx) +
helper.HiddenFor(modifiedEx)
);
}
}
and then:
#Html.StatusBox(model => model.RowInfo)
Needless to say that custom HTML helpers should be used to generate small portions of HTML. Complexity could grow quickly and in this case I would recommend you using an editor template for the RowInfo type.

Resources