1

How can I get my properties from a Model into my View with a foreach?

I know that I could use @Html.EditorFor(model => model.ID) but in my case this is not possible because I use one View for different Models (inherit from a BaseModel).

Model:

public class MyModel :  IEnumerable
{
    private PropertyInfo[] propertys 
    { 
        get
        {
            if (propertys != null) return propertys;

            string projectName = System.Reflection.Assembly.GetExecutingAssembly().GetName().Name;
            Type classtype = Type.GetType(string.Format("{0}.Models.{1}", projectName, FQModelname));
            PropertyInfo[] properties = classtype.GetProperties();

            return properties;
        }
    }

    public int ID { get; set; }

    public string Name { get; set; }

    //...

    public IEnumerator GetEnumerator()
    {
        return propertys.GetEnumerator();
    }
}

RazorView:

@foreach (var property in Model)
{
    // [Error] need Typeargument...?
    @Html.EditorFor(property);
}
jwillmer
  • 3,570
  • 5
  • 37
  • 73

2 Answers2

1

Have you tried @Html.EditorForModel() instead of @Html.EditorFor() ??

David C
  • 3,610
  • 3
  • 21
  • 23
  • of course but than I can´t define my own layout without creating a custom template and a good custom template isn´t trivial - i tried it ;-) – jwillmer Jun 27 '11 at 17:41
0

This could be done stronger typed but this is a quick implementation of the idea at least, you'll want to refine some of the concepts and get something working for your specific project.

void Main()
{
    BaseModel baseModelTest = new Concrete() { Test = "test property" };

    foreach ( var property in baseModelTest.EnumerateProperties())
    {
        var value = baseModelTest.GetPropertyValue(property.Name);
        value.Dump();
    }


}

public class EnumeratedProperty
{
    public string Name { get; private set; }
    public Type Type { get; private set; }
    public EnumeratedProperty(string PropertyName, Type PropertyType)
    {
        this.Name = PropertyName;
        this.Type = PropertyType;
    }
}

public abstract class BaseModel
{
    protected IEnumerable<PropertyInfo> PropertyInfoCache { get; set; }
    protected IEnumerable<EnumeratedProperty> EnumeratedPropertyCache { get; set; }
    protected BaseModel()
    {
        PropertyInfoCache = this.GetType().GetProperties();
        EnumeratedPropertyCache = PropertyInfoCache.Select(p=> new EnumeratedProperty(p.Name,p.GetType()));
    }
    public IEnumerable<EnumeratedProperty> EnumerateProperties()
    {
        return EnumeratedPropertyCache;
    }
    public object GetPropertyValue(string PropertyName)
    {
        var property = PropertyInfoCache.SingleOrDefault(i=>i.Name==PropertyName);
        if(property!=null)
            return property.GetValue(this,null);
        return null;
    }
}

public class Concrete : BaseModel
{
    public string Test { get; set; }
}

....

public static class ExtensionMethods
{
    public static MvcHtmlString EditorForProperty(this HtmlHelper html, BaseModel Model, EnumeratedProperty property)
    {
        // invoke the appropriate Html.EditorFor(...) method at runtime
        // using the type info availible in property.Type
        return ...
    }
}

....

@foreach (var property in Model.EnumerateProperties())
{
    // call the new extention method, pass the EnumeratedProperty type
    // and the model reference
    @Html.EditorForProperty(Model,property);
}
asawyer
  • 17,642
  • 8
  • 59
  • 87
  • I have tested it right now but it throws some errors. But I think this isn´t the right way because I need a way to get the properties to the `@Html.EditorFor`. The names of the properties aren´t enough because the fundtion should determine what field has to created :-( – jwillmer Jun 27 '11 at 15:26
  • @myName EditorFor needs to know the Type to create the html control for, which we had to throw away because we needed to be able to return any possible type, ie Object. You have a couple of solutions here - abandon this whole idea idea and find another route, possible using more view types, and partial views so that everything stays nice and strongly typed, or write your own HtmlHelper extension. THats the route that would probably work the best, as I am passing you back the property name AND type, so you would have both availible and be able to pick the right html tag to render at runtime. – asawyer Jun 27 '11 at 15:44
  • @asawyer I looked at [EditorExtensions.EditorFor](http://msdn.microsoft.com/de-de/library/ff406462.aspx) and i know that I have all needed parameters in the custom HtmlHelper but I don´t know how to invoke this method right. – jwillmer Jun 28 '11 at 17:44
  • I found the problem of invoking this method is worth a seperate question: [link](http://stackoverflow.com/questions/6533316/how-can-i-invoke-editorextensions-editorfor-in-my-htmlhelper) But right now it seems that it is not possible :-( – jwillmer Jun 30 '11 at 17:28
  • @myName - Well you do have one last resort. MVC is open source. You could always open up EditFor, examine how it works, and rework it into a form a little more friendly for your purposes. – asawyer Jun 30 '11 at 17:34
  • 1
    @myName - I haven't had the time to try working out the proper invoke myself yet, but I'll open up a test case and try later today. – asawyer Jun 30 '11 at 17:35
  • @asawyer sounds awesome, I think my skill-level isn´t that good to figure out a proper solution myself – jwillmer Jun 30 '11 at 17:39