Reputation: 6378
I'm learning ASP.NET MVC4, this in my first experience in Web development.
I'm dealing with a situation. In one of my controllers, I'm returning a IEnumerable<BaseClass>
to a View.
public class TestController : Controller
{
public ActionResult Index()
{
return View(Models);
}
// this static method is just for demo
static List<BaseModel> Models()
{
...
}
}
Imagine now, that we have 6 concrete class in BaseModels.
public class ConcreteModel1 : BaseModel { .. } // Must show view1
public class ConcreteModel2 : BaseModel { .. } // Must show view2
public class ConcreteModel3 : BaseModel { .. } // and so on..
public class ConcreteModel4 : BaseModel { .. }
public class ConcreteModel5 : BaseModel { .. }
public class ConcreteModel6 : BaseModel { .. }
When I want to display the data, each ConcrenteModel
has its own View
. As it's shown in the below image.
How can I accomplish this? If I wasn't very clear, please let me know Thanks.
Upvotes: 3
Views: 2013
Reputation: 67898
Here is a complete solution:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace MvcApplication1.Models
{
public abstract class BaseModel
{
public string Content { get; set; }
}
public class ConcreteModel1 : BaseModel { }
public class ConcreteModel2 : BaseModel { }
public class ConcreteModel3 : BaseModel { }
}
@model System.Collections.Generic.List<MvcApplication1.Models.BaseModel>
@{
ViewBag.Title = "CompositeView";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>
CompositeView</h2>
@foreach (var model in Model)
{
Html.RenderPartial(string.Format("_{0}", model.GetType().Name), model);
}
@model MvcApplication1.Models.ConcreteModel1
<h1>Concrete Model 1</h1>
@Model.Content
@model MvcApplication1.Models.ConcreteModel2
<h1>Concrete Model 2</h1>
@Model.Content
@model MvcApplication1.Models.ConcreteModel3
<h1>Concrete Model 3</h1>
@Model.Content
public ActionResult CompositeView()
{
List<BaseModel> model = new List<BaseModel>();
model.Add(new ConcreteModel1() { Content = "This is model 1." });
model.Add(new ConcreteModel2() { Content = "This is model 2." });
model.Add(new ConcreteModel3() { Content = "This is model 3." });
return View(model);
}
Upvotes: 5
Reputation: 37523
I would actually create a custom model whose contents were your IEnumerable<BaseModel>
that had its own built in methods for retrieving a specific model by type. That way you can render partial views and send into them the specific ConcreteModel
typed properly. Maybe something like:
public class UltraModel
{
// I recommend using an interface rather than a base class
// to avoid potentially confusing types
public IBaseModel Models { get; set; }
public T getModelByType<T>()
{
return (T)Models.Where(x => x is T).FirstOrDefault();
}
}
Then in your global view you can render partials with:
RenderPartial("ConcreteViewName", Model.getModelByType<ConcreteModel1>());
Note: Treat the above as psuedo-code. It will likely need to be tweaked to work just right.
Upvotes: 0
Reputation: 1869
You can have a composite view for the TestView
and then render partial views for each of the smaller views. To accomplish this the models for the smaller views will need to be available from the model passed to the composite view.
Something like this: (TestView.cshtml)
@model ParentViewModel
@Html.RenderPartial("View1", Model.SubModel1)
@Html.RenderPartial("View2", Model.SubModel2)
@Html.RenderPartial("View3", Model.SubModel3)
You then have separate views, like: (View1.cshtml)
@model SubViewModel1
<!-- Whatever -->
Upvotes: 3