2

I'm trying create a custom HTML helper extension method that takes an object htmlAttributes and then get the passed in values (via reflection) and add to them into a Dictionary<string, object>. Unfortunately, this does not work although there is an overload in the InputExtensions class that takes a Dictionary<string, object> htmlAttributes as a parameter.

The problem is that this dictionary is not being processed properly somewhere inside the razor engine (I guess...). Here's how it is being output as HTML:

<input name="FirstName" id="FirstName" type="text" Values="System.Collections.Generic.Dictionary`2+ValueCollection[System.String,System.Object]" Keys="System.Collections.Generic.Dictionary`2+KeyCollection[System.String,System.Object]" Count="3" Comparer="System.Collections.Generic.GenericEqualityComparer`1[System.String]"/>

And here's my code:

    Dictionary<String, Object> attributes = new Dictionary<String, Object>();
    attributes.Add("readonly", "readonly");
    PropertyInfo[] properties = htmlAttributes.GetType().GetProperties();
    foreach (PropertyInfo propertyInfo in properties)
    {                                        
        if (propertyInfo.Name.Equals("class"))
        {
            attributes.Add("class", String.Format("{0} {1}", "readOnly", propertyInfo.GetValue(htmlAttributes, null)));
        }
        else
        {
            attributes.Add(propertyInfo.Name, propertyInfo.GetValue(htmlAttributes, null));
        }
    }

    genericMethod = methodInfo.MakeGenericMethod(new[] { typeof(TModel), typeof(TProperty) });
    result = genericMethod.Invoke(null, new object[] { helper, expression, (Dictionary<String, Object>)attributes }) as MvcHtmlString;

P.S: This is a follow up to this question.

1 Answer 1

2

You should be able to call the TextBoxFor method directly and pass in the expression and your new html attributes.

public static IHtmlString Test<TModel, TProperty>(this HtmlHelper<TModel> helper, Expression<Func<TModel, TProperty>> expression, object htmlAttributes)
{
    Dictionary<String, Object> attributes = new Dictionary<String, Object>();
    attributes.Add("readonly", "readonly");
    PropertyInfo[] properties = htmlAttributes.GetType().GetProperties();
    foreach (PropertyInfo propertyInfo in properties)
    {
        if (propertyInfo.Name.Equals("class"))
        {
            attributes.Add("class", String.Format("{0} {1}", "readOnly", propertyInfo.GetValue(htmlAttributes, null)));
        }
        else
        {
            attributes.Add(propertyInfo.Name, propertyInfo.GetValue(htmlAttributes, null));
        }
    }

    //call the input tag
    return helper.TextBoxFor(expression, htmlAttributes);
}
Sign up to request clarification or add additional context in comments.

4 Comments

There's a RouteValueDictionary constructor overload that accepts object as well. No need to use reflection.
The overload for that just does the same thing but you're right that you can use that easier.
I tried to create an instance of RouteValueDictionary that takes the attributes dictionary, and then pass that instance as the parameter of the invoked method, but still that did not change anything! All I need to do is be able to modify the htmlAttributes object, so if I could get rid of the dictionary altogether that would be perfect.
Ok, I see your problem. What are you trying to return from your extension? Just the string of html attributes or the entire tag itself?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.