I'm trying to accomplish something like this. I feel like it's possible, and if not probably an oversight in the MVC framework?
View:
<%# Page Language="C#" Inherits="System.Web.Mvc.ViewPage<List<MyViewModel>>" %>
...
<% foreach (MyViewModel vm in Model) {
Html.RenderPartial("MyViewModelPartial", vm);
} %>
The partial view being an editable form, strongly typed to a single MyViewModel, and use the DataAnnotations on the MyViewModel class to validate
Controller:
public ActionResult FooController(List<MyViewModel> vml)
{
...
}
Is this possible? This seems like the most logical way to build grid/table structures in MVC(with each partial view being a table row) but I can't seem to get it to work and I end up using FormCollection in my controller to loop through the whole dang form, and it's just messy.
See:
http://haacked.com/archive/2008/10/23/model-binding-to-a-list.aspx
Which is linked to from:
Complex model binding to a list
How ASP.NET MVC: How can I bind a property of type List<T>?
Related
I have a usercontrol named "LoginUserControl.ascx" which I have placed in a master page.
Header of "LoginUserControl.ascx"
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<MultiTechnologyWeb.Models.loginmodel>" %>
Then I used the below code to show the usercontrol in the masterpage.
<% Html.RenderPartial("LoginUserControl"); %>
On first run the page "index" is loaded.
Notice the header of the "index" page, no model is specified. Thus page load successfully
<%# Page Title="" Language="C#" MasterPageFile="~/Views/Shared/MT.Master" Inherits="System.Web.Mvc.ViewPage<dynamic>" %>
Now I click on the link to open register.aspx. I got the below error
The model item passed into the dictionary is of type 'MultiTechnologyWeb.Models.registermodel', but this dictionary requires a model item of type 'MultiTechnologyWeb.Models.loginmodel'.
Header of "register.aspx" page
<%# Page Title="" Language="C#" MasterPageFile="~/Views/Shared/MT.Master" Inherits="System.Web.Mvc.ViewPage<MultiTechnologyWeb.Models.registermodel>" %>
So to my understanding model is being interchanged, so anybody can please help me on how to resolve this issue
More Explanation.............LATEST
I have debug, i know that the crash is occuring after the actionresult for register is finished execution.
Code below is for actionresult "register"
public ActionResult register()
{
registermodel model;
//some code here
return View("register",model);
}
So i'm just returning one type of model that is "registermodel", Would it be possible to return another model such as "loginmodel" by using a list or array to return multiple models in the same view.
You should use <% Html.RenderAction("Logon","Account"); %> in your MasterPage instead of using RenderPartial and in this action you just return the login partial you want to use in the header
public ActionResult Logon(){
// do your stuff
return PartialView("LoginUserControl");
}
By this way you could pass the loginmodel to the LogInPartial and pass registermodel to the register page
Please not that RenderAction and RenderPartial are not the same.
RenderPartial will render only the view. While RenderAction will make a new MVC roundtrip, by making a new instance of the controller etc and returning the result.
To solve your issue you could pass in the MultiTechnologyWeb.Models.loginmodel where you call <% Html.RenderPartial("LoginUserControl"); %>. It would look like this:
<% Html.RenderPartial("LoginUserControl", new MultiTechnologyWeb.Models.loginmodel()); %>
Or:
<% Html.RenderPartial("LoginUserControl", Model.LoginModel); %>
If you're not wanting to send a model to your partial view, which I've wanted to do in the past, you do have to at least pass something to the RenderPartial method.
This was the only method I could find that allowed me to now have to pass a model. I tried passing null and it continued to pass the parent model
<% Html.RenderPartial("LoginUserControl", new ViewDataDictionary()); %>
Short of overriding ViewData.TemplateInfo.HtmlFieldPrefix with an empty string, is there a way to keep the prefix from coming through on a nested set of strongly-typed EditorFor or DisplayFor helper calls?
Here's the ugly markup/code I have working so far:
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<System.Web.Mvc.SelectList>" %>
<% ViewData.TemplateInfo.HtmlFieldPrefix = ""; %>
<%=Html.DropDownList("sort", Model)%>
I've tried the *For overload that allows specifying htmlFieldName but that only changes the immediate level. If I have a prefix at the point of that call, I just change what is appended to the prefix.
I could write the template markup by hand, but doing so for a SelectList object seems like I will just end up copying over the MVC source with a single tweak since it involves object data binding logic.
If you have a property on your view model, rather than just doing dropdown list directly on the model, you can put a DataAnnontation attribute on it.
public class MyModel
{
[Display(Name="Your Favorite Choices")]
public string[] Choices {get; set;}
}
then in your code
<%= Html.LableFor(m => m.Choices) %><br />
<%=Html.DropDownList("sort", Model.Choices)%>
Should use that name.
[Hope I got it right from memory. :)]
Here's the MSDN link:
http://msdn.microsoft.com/en-us/library/system.componentmodel.dataannotations.displayattribute.displayattribute.aspx
Not sure if I understand your question, but, if you render the "child" views as partials instead of EditorFor then the fields will not be prefixed.
I'm following this MVC tutorial and when I add a View for the Edit action, Model is null in the following snippet on the .aspx page:
<%= Html.TextBox("Id", Model.Id) %>
I'm learning MVC, so please understand if I'm doing a dumb thing. But as far as I can see, I've following the steps in the tutorial pretty well. And actually added the Create action and it works correctly.
Ideas appreciated.
Is your view strongly typed?
<%# Page Language="C#" MasterPageFile="~/Views/Shared/TwoColumnUI.Master" Inherits="System.Web.Mvc.ViewPage<MyObject>" %>
then you would need to pass in an object of type MyObject from your controller action method
return View(new MyObject() { Id = 42 } );
Did you set the model in the controller? What does your controller method look like? Are you just returning View()? You need to pass the model as a parameter to that call like they do in the example:
return View(movieToEdit);
Is it possible to return a complex type from a controller to a view in asp.net mvc? All the examples I have looked at so far demonstrate passing simple intrinsic types like int, string....
You can pass any object type to the view using the ViewData Dictionary.
Just put in your controller:
ViewData["example"] = (YourObject)data;
And then in your view:
<%= ((YourObject)ViewData["example"]).YourProperty %>
And if you want to pass your object as your View model then:
return View("viewname", (YourObject)data);
And make sure your view looks like this:
<%# Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<YourObject>" %>
You can create a viewmodel that's then used in the strongly typed view. You can check out this blogpost by Stephen Walther that explains it. I started out just dumping stuff in viewdata, but that gets confusing pretty quickly ;).
Use a ViewModel for your page.
you could use a view model containing both complex and simple objects, for example:
public class MyComplexViewModel
{
public Address UserAddress { get; set;}
public List<string> ValidZipCodes { get; set; }
public string Message { get; set; }
}
If your view inherits the generic ViewPage with something like this
<%# Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<MyComplexViewModel>" %>
you could then in the view use the view model as Model.:
<%= Html.Encode(Model.UserAddress.SomeAddressProperty) %>
<%= Html.Encode(Model.ValidZipCodes.Count) %>
<%= Html.Encode(Model.Message) %>
My action creates a strongly typed viewdata, which is passed to my view.
In the view, I pass the Model to the render partial method.
public ActionResult Index()
{
ViewDataForIndex vd = new ViewDataForIndex();
vd.Users = Users.GetAll();
return View(vd);
}
public class ViewDataForIndex: ViewData
{
public IList<User> Users {get;set;}
}
now in the view:
<%# Page Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<ViewDataForIndex>" %>
<% Html.RenderPartial("~/controls/blah.ascx", ViewData.Model); %>
and in blah.ascx:
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl" %>
how do I access my model now?
if I wanted to create a strongly typed class for my ViewUserControl, how would I do that? inherit from?
One: Inside the ascx:
<%= Model.YourProperty %>
Two: Provide a type Argument to ViewUserControl:
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<String>" %>
I like #jfar's second approach better as it allows for easier modification if you ever decide to pass a more complex model to the view.
So you may pass a class that has multiple properties and/or more child objects.
If you inherit from the object now, then all you need to do is to inherit from your complex object and change one piece of code, as well as add the new properties, and your done.
More specifically to jfar's answer:
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<ViewDataForIndex>" %>
If your parent page has a model of type ViewDataForIndex, calling the child with the same ViewData.Model will also pass an object of type ViewDataForIndex.