Juan Carlos Oropeza
Juan Carlos Oropeza

Reputation: 48197

MVC Helper Object and Property name

I made my first MVC helper to split long strings in a table and I also validate if string is NULL and user can send NullString ='NA' to show instead of empty string.

public static IHtmlString Split(
        this HtmlHelper helper, 
        string source, 
        int size = 30, 
        string NullString = "")

Now I have the situation where the string is inside an object and this object can also be null.

@if (item.city == null)
{
   <td>NA</td>
}
else
{
   <td class="format">@item.city.name</td>
}

I want to do something generic, where I get an object and a property name. Then I can get the value from the object.

public static IHtmlString Split(
        this HtmlHelper helper, 
        OBJECT source, 
        STRING property,
        int size = 30, 
        string NullString = "")

Is there a way I can get source.property() from a generic object?

by request full code of my current function

public static IHtmlString Split(this HtmlHelper helper, string source, int size = 30, string NullString = "")
    {
        TagBuilder tb = new TagBuilder("td");
        tb.Attributes.Add("class", "format");

        if (source == null)
        {
            tb.InnerHtml = NullString;
        }
        else if (source.Length < size)
        {
            tb.InnerHtml = source;
        }
        else
        {
            int middle = source.Length / 2;
            int before = source.LastIndexOf(' ', middle);
            int after = source.IndexOf(' ', middle + 1);

            if (before == -1 || (after != -1 && middle - before >= after - middle))
            {
                middle = after;
            }
            else
            {
                middle = before;
            }

            string s1 = source.Substring(0, middle);
            string s2 = source.Substring(middle + 1);

            tb.InnerHtml = s1 + "<br />" + s2;
        }
        MvcHtmlString result = new MvcHtmlString(tb.ToString(TagRenderMode.Normal));
        return result;
    }

Upvotes: 1

Views: 816

Answers (2)

Rob Purcell
Rob Purcell

Reputation: 1285

One approach would be to get the type of the object and then check for the existence of a property of the given name. Your helper method would accept the following arguments:

public static IHtmlString Split(
    this HtmlHelper helper,
    object source,
    string property = "",
    int size = 30,
    string NullString = "")

Then you would get the System.Type of the source object and decide whether to treat it as a string, or try to get the value of some specified property.

        var stringToSplit = string.Empty;
        if (source == null)
        {
            stringToSplit = NullString;
        }
        else if (string.IsNullOrEmpty(property))
        {
            stringToSplit = source.ToString();
        }
        else
        {
            Type type = source.GetType();
            var propertyInfo = type.GetProperty(property);
            if (propertyInfo != null)
            {
                var propertyValue = propertyInfo.GetValue(source);
                stringToSplit = propertyValue != null ? propertyValue.ToString() : NullString;
            }
            else
            {
                stringToSplit = NullString;
            }
        }

Then you would check the length of stringToSplit and split it if necessary.

Upvotes: 1

shenku
shenku

Reputation: 12448

This is how I might do it.

Use Razor templates to create an extension method, that accepts an object to check and the lambda to grab the string.

public static class HtmlHelperExtensions
{
    public static IHtmlString AlternateTemplates<TModel>(this HtmlHelper htmlHelper, TModel model,
        Func<TModel, string> stringProperty, Func<string, HelperResult> template,
        Func<object, HelperResult> nullTemplate) where TModel : class
    {
        HelperResult result;

        if (model != null)
        {
            var propertyValue = stringProperty.Invoke(model);
            var splitValue = YourCustomSplitFunction(propertyValue); // TODO: Impliment yout split function to return a string (in this case)

            result = template(splitValue);
        }
        else
        {
            result = nullTemplate(null);
        }

        htmlHelper.ViewContext.Writer.Write(result);

        return MvcHtmlString.Empty;
    }
}

Given a model like this:

public class ViewModel
{
    public Region Region { get; set; }
}

public class Region
{
    public string City { get; set; }
}

My controller action as an example:

In my view I could call:

@Html.AlternateTemplates(Model.Region, x => x.City, @<div>@item</div>, @<div>N/A</div>)

So, it's checking if the object I send in (in this case it's the Region) is not null, then grab the property I specified (in this case City), then render it against my first html/razor template, otherwise use the alternate.

Easy.

Some reading: http://www.prideparrot.com/blog/archive/2012/9/simplifying_html_generation_using_razor_templates

Upvotes: 1

Related Questions