2

I want to expose a globalized help text on to an MVC view.

Currently the code looks like this,

Custom attribute class

 class HelpTextAttribute : Attribute
 {
     public string Text { get; set; }
 }

View model property and custom annotation

[HelpText(Text = "This is the help text for member number")]
public string MemberNo { get; set; }

(The literal string must come from a resource class)

The question is how do i write an Html extension that could do the following

@Html.HelpTextFor(m => m.MemberNo)
Ashley Medway
  • 7,151
  • 7
  • 49
  • 71
Ahsan
  • 2,488
  • 2
  • 22
  • 44
  • What would this `HelpTextFor` emit? Some html containing the text provided? – haim770 Jun 18 '15 at 13:29
  • Yes it could simply be This is the help text for member number – Ahsan Jun 18 '15 at 13:30
  • 2
    Any reason to not use the [`Description`](https://msdn.microsoft.com/en-us/library/system.componentmodel.dataannotations.displayattribute.description.aspx) property of `DisplayAttribute`? – Richard Jun 18 '15 at 13:30
  • Description is not "Help" is it? – Ahsan Jun 18 '15 at 13:30
  • Where exactly is your problem? Do you not know how to write extension methods? Do you not know how to deal with lambda parameters? Something else? Do you have any code that you've tried that doesn't work? Perhaps you could start with writing a non-extension method... Currently this question is rather broad and could do with being more focussed. – Chris Jun 18 '15 at 13:30
  • To begin with, how to write an extension that could pickup an annotation would be a start. i am not familiar with such technique. – Ahsan Jun 18 '15 at 13:32
  • Checkout the docs: "The Description property is typically used as a tooltip or description UI element": which sounds exactly like what you want. (You would still needs a helper for displaying it in the way you want.) – Richard Jun 18 '15 at 13:32
  • How to do the helper: you can always look at the source of the `LabelFor` helper which reads the `Name` property of the `DisplayAttribute` associated with the specified model property. – Richard Jun 18 '15 at 13:34
  • LabelFor helper source is open to read? sorry i am not sure where i can read it from? – Ahsan Jun 18 '15 at 13:35
  • @Ahsan You should not edit your question to include the solution, If the accepted answer is not adequate then you should add your own answer. – Ashley Medway Jun 22 '15 at 15:51

3 Answers3

4

You're gonna need to extend the HtmlHelper class with the following:

public static MvcHtmlString HelpTextFor<TModel, TValue>(this HtmlHelper<TModel> helper, Expression<Func<TModel, TValue>> expr)
{
    var memberExpr = expr.Body as MemberExpression;

    if (memberExpr != null)
    {
        var helpAttr = memberExpr.Member.GetCustomAttributes(false).OfType<HelpTextAttribute>().SingleOrDefault();

        if (helpAttr != null)
            return new MvcHtmlString(@"<span class=""help"">" + helpAttr.Text + "</span>");
    }

    return MvcHtmlString.Empty;
}

Then use it as requested:

@Html.HelpTextFor(m => m.MemberNo)

Also, be sure to mark your HelpTextAttribute with the public modifier.

haim770
  • 48,394
  • 7
  • 105
  • 133
  • Thanks for taking the time to answer, How do I extend this further to localize the help string. (At least a hint towards the right direction) – Ahsan Jun 18 '15 at 14:06
  • Do you currently have a resources file with localized strings? – haim770 Jun 18 '15 at 14:08
  • Yes i do, i use it for converting the @Html.LabelFor via the Display attribute. – Ahsan Jun 18 '15 at 22:26
  • You can simply replace the `helpAttr.Text` part in the code with a call to your `ResourcesManager` and retrieve the localized text. But, if you want to have the same behavior as in your `Html.LabelFor` calls, provide an example of how you're decorating the displayed property. – haim770 Jun 19 '15 at 07:09
  • [Display(Name = "MemberNumberLabel", ResourceType = typeof(ModelResources))] – Ahsan Jun 19 '15 at 11:00
0

Maybe you are doing things wrong because i think that DataAnnotations and MVC Helpers are different things.

i would do something like this: a helper view on my App_Code with the code:

@helper HelpTextFor(string text) {
     <span>@text</span>
}

and then use it as you wrote.

Phoenix_uy
  • 3,173
  • 9
  • 53
  • 100
0

About localizing the string (I cannot comment because I do not have enough points yet)

Add the following attributes to your HelpTextAttribute

 public string ResourceName { get; set; }
 public Type ResourceType { get; set; }

and then adjust the HelpTextFor as follows:

 var helpAttr = memberExpr.Member.GetCustomAttributes(false).OfType<HelpTextAttribute>().SingleOrDefault();

            Assembly resourceAssembly = helpAttr.ResourceType.Assembly;
            string[] manifests = resourceAssembly.GetManifestResourceNames();

            // remove .resources
            for (int i = 0; i < manifests.Length; i++)
            {
                manifests[i] = manifests[i].Replace(".resources", string.Empty);
            }

            string manifest = manifests.Where(m => m.EndsWith(helpAttr.ResourceType.FullName)).First();
            ResourceManager manager = new ResourceManager(manifest, resourceAssembly);

            if (helpAttr != null)
                return new MvcHtmlString(@"<span class=""help"">" + manager.GetString(helpAttr.ResourceName) + "</span>");

Please see the following link on why to remove .resources C# - Cannot getting a string from ResourceManager (from satellite assembly)

Best regards Dominic Rooijackers .NET software developer

Community
  • 1
  • 1
Dominic
  • 1
  • 1