4

I want to make dynamic view that show list of entity properties.

I create these models

  public class PersonModel
{
    public string FirstName { get; set; }
    public string LastName { get; set; }

}

  public class EmployeeModel : PersonModel
    {
        public string CompanyName { get; set; }

      }

 public class StudentModel : PersonModel
    {
        public string SchoolName { get; set; }

    }

I want one view that show list, the view dynamically generated for examples columns and data appear in list.

Example when open employee I will show following:

enter image description here

and when Open student I will show following:

enter image description here

what easiest way to make my view dynamical and contain the columns and data I want?

tereško
  • 58,060
  • 25
  • 98
  • 150
Duha
  • 811
  • 1
  • 12
  • 26
  • You can create two partial views typed by different model and then use that in your view. probably have your action method switch that per model and return to the view. – Rahul Jan 06 '16 at 15:49
  • Pretty difficult. Hopefully my answer does what you need. – Steve Harris Jan 06 '16 at 16:43

2 Answers2

3

I hope this makes as much sense as I think it does!

As List<PersonModel>, List<EmployeeModel> and List<StudentModel> are actually considered completely different, you will need a way to overcome that issue. I use a generic container class:

public interface IGenericContainer
{
    dynamic Data { get; }
}

public class GenericContainer<T> : IGenericContainer
{
    T _Data { get; set; }
    public GenericContainer(T data)
    {
        _Data = data;
    }
    dynamic IGenericContainer.Data
    {
        get { return _Data; }
    }
}

public class GenericContainer
{
    public static GenericContainer<T> Create<T>(T data)
    {
        return new GenericContainer<T>(data);
    }
}

You then need a generic view that uses this. Put this in Shared/DisplayTemplates/GenericGrid.cshtml

@using System.Reflection;
@using System.Text;
@{
    Layout = null;
}
@model IGenericContainer
@{
    IEnumerable<PropertyInfo> properties = null;
    if (Model.Data.Count > 0)
    {
        properties = Model.Data[0].GetType().GetProperties();
    }
}
<div>
@if (properties != null)
{
    <table>
        <thead>
            <tr>
                @foreach (var prop in properties)
                {
                    <td>@prop.Name</td>
                }
            </tr>
        </thead>
        <tbody>
            @for (int i = 0; i < Model.Data.Count; i++)
            {
                <tr>
                @foreach (var prop in properties)
                {
                    <td>@prop.GetValue(Model.Data[i])</td>
                }
                </tr>
            }
        </tbody>
    </table>
}
</div>

To use this you will need to add this to your view:

@Html.DisplayFor(m => GenericContainer.Create(Model.PersonList), "GenericGrid")

And PersonList is a property in your model of type List<PersonModel> or a list of any of your models.

Steve Harris
  • 5,014
  • 1
  • 10
  • 25
  • awesome, I like it , is there way to load parent class properties then the driven class , for example above for employee I need first name , last name , then company name? – Duha Jan 07 '16 at 07:49
  • Try changing `GetProperties()` to `GetProperties().OrderBy(x => x.MetadataToken)` – Steve Harris Jan 07 '16 at 09:10
  • If that doesn't work then this question has an answer that looks like it might do the job: http://stackoverflow.com/questions/358835/getproperties-to-return-all-properties-for-an-interface-inheritance-hierarchy – Steve Harris Jan 07 '16 at 09:11
1

I'm not really sure if I have understood your requirements properly, but if you wanted to display each property of your model dynamically as a column header, then you could try the following:

In your view, you can call the GetProperties method on the type and recursively add a column for each property:

@model PersonModel
@if (Model != null)
{
    <table style="width:100%">
        <tr>
            @foreach (string property in Model.GetType().GetProperties().Select(x => x.Name).ToList())
            {
            <td>@property</td>
            }
        </tr>
    </table>
}

You can use this example to populate the header columns of a table before you populate the rows. To populate the rows you would need a list of PersonModel and do a foreach on this similar to what I have shown you for the column headers.

Hope that helps.

Brad
  • 554
  • 4
  • 7
  • thank you, I need general view for any model . so view can't now that type of the model – Duha Jan 07 '16 at 07:52