Dynamically call textboxfor with reflection

依然范特西╮ 提交于 2019-11-30 20:29:16

问题


The end result of what I am trying to do is build a form dynamically by reflecting an object and it's properties.

I've created HtmlHelper methods that call TextBoxFor and CheckBoxFor and so on, but now I need help figuring out how to properly reflect the property when passing it to Html.TextBoxFor

Here's the helper method:

public static MvcHtmlString FormTextBox<TModel>(this HtmlHelper<TModel> helper, String id, String property_name, object model, RouteValueDictionary attributes)
    {          
        Type model_type = model.GetType();

        return helper.TextBoxFor(model_object => model_type.InvokeMember(property_name, BindingFlags.ExactBinding | BindingFlags.GetProperty, null, model, null));
    }

But it breaks on the return with this error code:

Templates can be used only with field access, property access, single-dimension array index, or single-parameter custom indexer expressions.

Basically I want to take what would be this:

@Html.TextBoxFor(model => model.Name)

And turn it into this:

@FormHelpers.FormTextBox("Name", model)

And have it output the same thing.

UPDATE

I will restate this, as I have made some progress in solving the problem.

I've created an Expression from Expression.PropertyOrField that creates exactly what I am looking for. However I can't get the TextBoxFor function to accept it.

Expression fieldExpr = Expression.PropertyOrField(Expression.Constant(model),property_name);

        return helper.TextBoxFor(Expression.Lambda<Func<TModel>>(fieldExpr, null).Compile()());

Any ides on how to properly pass the Expression to the function?


回答1:


Ok, I solved this problem by building a lambda expression using the property name and the type of the object being passed in. My function looks like this:

ParameterExpression fieldName = Expression.Parameter(typeof(object), property_name);
        Expression fieldExpr = Expression.PropertyOrField(Expression.Constant(model), property_name);
        Expression<Func<TModel, object>> exp = Expression.Lambda<Func<TModel, object>>(fieldExpr, fieldName);

        return helper.TextBoxFor(exp);

Example:

@{ Name myname = new Name();}
@Html.FormTextBox("first", myname)

fieldName builds an expression for the left hand side (first) and then fieldExpr builds the body of the expression with the class name and property name.

exp ends up looking like this:

first => value(DynamicForm.Models.Name).first

Now all I need to do is make sure that my data annotations still work.




回答2:


To get a property using reflection, use code like this:

var prop = model_type.GetProperty(property_name);
//then in your loop:
prop.GetValue(model, null)

Or if you're only going to get the property from one object, make it one line:

model_type.GetProperty(property_name).GetValue(model, null);


来源:https://stackoverflow.com/questions/7208911/dynamically-call-textboxfor-with-reflection

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!