I was originally developing a project for WPF, using MVVM, which had the benefit of allowing me to populate a list of views that I wanted available. Each view had a "Next" button that would progress to the next view in the list.
However, now I am trying to do the same in ASP.NET MVC. This is my first time using MVC, but I have an XML file, from which I need to generate this UI. These views, which are chosen from the script, also have components in them that are dynamic -- sometimes ViewA might need 3 "input views" nested in it, sometimes it might need 1.
I was achieving that before with ListBox, ItemsSource, and DataTemplate. So my question is this: how can I dynamically populate which views to display, and (more importantly) how can I dynamically fill those views with x number of control A, and y number of control B?
First off, a high-level overview of the project structure...
YourProjectName
Controllers
ProductController.cs
Models
ProductViewModel.cs
Views
_ProductPartial.cshtml
ListProducts.cshtml
ProductViewModel.cs
public class ProductViewModel
{
public string Name { get; set; }
public string Description { get; set; }
}
ProductController.cs
public class ProductController : Controller
{
public ActionResult Index()
{
// Create your model (this could be anything...)
var model = new List<ProductViewModel>
{
new ProductViewModel { Name = "Apple", Description = "A red apple" },
new ProductViewModel { Name = "Orange", Description = "An orange orange" }
};
// Return the main view and your model
return View("ListProducts", model);
}
}
_ProductPartial.cshtml
#model YourProjectName.Models.ProductViewModel
<h1>#Model.Name</h1>
<p>#Model.Description</p>
ListProducts.cshtml
#model System.Collections.Generic.List<YourProjectname.Models.ProductViewModel>
#foreach (var product in Model)
{
Html.Partial("_ProductPartial", product)
}
Summary
Now if you request that controller action (localhost/Product/Index or whatever it ends up being for you), the controller will create the model, render the parent view, and the parent view will render as many of the product partial views as necessary depending on the product model collection we defined in the controller. Views and partial views don't require models, but I imagine you will be using a model class of some sort to help you determine what/where/how many partial views to render in your parent views. This is about as basic as it gets but it should get you started in using partial views.
Related
I have a tree structure of objects (as in picture below). Classes Descendant1 and Descendant2 are to be viewed in the same way as Form class(the root class). I wanted to create a partial view for that, however, I need to have a model in the view as I am using properties from the model(such as Name from the root class)
This is my code of FormView that is to be in the partial view:
<div>
#foreach (var subForm in Model.SubForms)
{
Html.RenderPartial(partialView, subForm);
}
<div>#Model.Name</div>
</div>
I was wondering if it was possible to create a partial view that can have multiple models? Do I create one controller for all the descendant classes together? Otherwise, do you have any ideas how to proceed?
I was wondering if it was possible to create a partial view that can have multiple models?
Yes, make a view model for those 3 classes. Example below is named FormViewModel.
public class FormViewModel{
public class Descendant1 {get;set;}
public class Descendant2 {get;set;}
public class Descendant3 {get;set;}
}
Then in your view you could do;
#foreach (var subForm in Model.SubForms)
{
FormViewModel fmv = new FormViewModel();
// access its class properties
fmv.Descendant1.SubForms.Add(new Form(){ // assign properties });
// pass the view model to the partial view
Html.RenderPartial(partialView, fmv);
}
In ASP .NET WebForms, it was possible to create properties and methods in WebControl pages that were accessible from the host page. Is this possible in MVC?
I'd like to add custom properties to a partial view, render it on the main view and then have the main view access those properties. What are my options?
This problem can have many solutions. F.e. you can use complex main view model, that have a partial view model property:
public struct PartialViewModel
{
public string Foo { get; set; }
public int Bar { get ; set; }
}
. . .
public struct MainViewModel
{
public double Baz { get; set; }
public PartialViewModel Qux { get; set; }
}
Then you can build MainViewModel in an action's code:
public ActionResult SomeAction(int id)
{
var model = ModelRepostiory.GetById(id);
var viewModel = new MainViewModel
{
Baz = model.Baz,
Qux = new PartialViewModel
{
Foo = model.Partial.Foo,
Bar = model.Partial.Bar,
},
};
return View(viewModel);
}
MainView.cshtml
#model MainViewModel
. . .
<div>
<p>Additional info:</p>
#Partial("partial", Model.Qux)
</div>
PartialView.cshtml
#model PartialViewModel
<p>Foo: #Model.Foo</p>
<p>Bar: #Model.Bar</p>
I believe the ViewBag will help you in this
You can set ViewBag properties with
ViewBag.MyProperty = "this is a string";
and then retrieve them in other parts of the view.
This only makes sense in an event based system. The state of a control changes and the container needs to react to those changes.
In ASP.NET MVC the container main view
passes the data to its partials. If a partial needs to change the state of the application it posts the changes to a controller action. The controller action then supplies the changed model to the main view and the the contained partials.
I have seen similar questions here regarding my question but I am unable to find a suitable solution for my purpose. So I started working with the MVC and had to create a simple wizard. I created the Parent View model as,
public class WizardSteps
{
public int CurrentStepIndex { get; set; }
public WizardStep1 Step1 { get; set; }
public WizardStep2 Step2 { get; set; }
public WizardStep3 Step3 { get; set; }
public WizardSteps()
{
CurrentStepIndex = 1;
Step1 = new WizardStep1();
Step2 = new WizardStep2();
Step3 = new WizardStep3();
}
}
Now I have created three partial views for each of my wizard step. For every view I used the parent model,
#model eFormation_MVC.Models.WizardSteps
For each of the fields on each of the Partial Views I used controls like this inside forms,
#Html.LabelFor(m => m.Step1.FirstName, new { #class = "col-sm-3 control-label" })
#Html.LabelFor(m => m.Step2.Address, new { #class = "col-sm-3 control-label" })
This is brief code for just giving the idea what I have done so far. I have different controller methods for each of the Partial View. I pass the Parent Model WizardSteps to the controller and pass it back to next Partial View. SO for all Partial View single model is used which has child model. Now when I post the model from Second Partial View then all the values in WizardSteps.Step1 become null. I also know that this is the actual behavior but my question is how to persist the values. What can be the proper way of doing this so that the values for every Step is not lost from the Parent model.
Edit:
Each partial view has its own form and I am sending the parent model WizardSteps to the controller on form submit of each partial view. The problem is that when I submit Partial View for Step 2 then the values for Step 1 in the WizardSteps becomes null. I know this happens because there are no fields for Step 1 on Step 2 partial view and controller think values as null and does not persists it.
On some related question it is suggested to Serialize the models and store it on the View and send it back to controller and de-serialize it. Some has use Sessions or TempData for storing the models but I want something which is done with models. There is a question for using MVCWizard at MVCWizard.Wizard - Using Complex Models but the answer to that question is so vague that I am unable to grasp it. I want something similar to the MVCWizard with the use of Merge functionality but couldn't find any example of doing so. Need help with this.
I`m writing an ASP.Net MVC application with Razor.
Assume that I have HomeController and some views for it.
1. View1
2. View2
3. View3
All this views use common _MyLayout file, which should look like this:
When the links are clicked, the views are rendered by RenderBody() method.
Each view is strongly typed: it requires its own Model.
Everything was fine untill I decided to add special Model to _MyLayout view.
But now I get error
The model item passed into the dictionary is of type 'TestUp.Models.UserModels.PendingTestsModel', but this dictionary requires a model item of type 'TestUp.Models.UserModels.UserNavigationModel'.
Here is controllers code
public ActionResult View1()
{
ModelForView1 model = new ModelForView1();
return View(model);
}
public ActionResult View2()
{
ModelForView2 model = new ModelForView2();
return View(model);
}
public ActionResult View3()
{
ModelForView3 model = new ModelForView3();
return View(model);
}
Shortly speaking if layout view doesn`t require model, specific method for View is invoked,
model is created, passed to view and everything is ok. But now layout requires model as well so it crashes.
The question is: how do I elegantly resolve this problem?
Desired workflow is:
View1 is requested
Method in controller for this view is called, model instance created, passed to view
Some method for layout is called, model for layout created, passed to layout.
Is it possible to make things work somehow like this?
Thanks.
Create a base model type and have your specific view models extend it. This base model can have a property of type UserNavigationModel. The layout can accept the base model and use the new property as the model for the navigation menu.
public abstract class ModelBase
{
public UserNavigationModel NavigationModel { get; set; }
}
public class ModelForView1 : ModelBase { ... }
public class ModelForView2 : ModelBase { ... }
public class ModelForView3 : ModelBase { ... }
View1:
#model ModelForView1
Layout:
#model ModelBase
#* use Model.NavigationModel for nav bar *#
I have a view model as such:
public class MyViewModel
{
public MyObject myObject{ get; set; }
public List<MyList> myList{ get; set; }
}
I have a view with a form strongly typed to MyViewModel
This view allows you to enter values for the properties of MyObject, as well as create a list of MyList objects. The List part works fine although I thought that would be the more difficult of the two.
Assuming MyObject has a property Description I create a textbox to enter the value as such:
#Html.EditorFor(x => x.myObject.Description);
The text box renders with an id of MyObject_Description...The problem is when I post this to my controller action, MyObject does not get bound at all(althought the list items do as they recieve the appropriate IDs of "MyViewModel_MyList[guid].myListValue")
What am I doing wrong here??
EDIT: more info
The first line of the view is:
#model MyApp.ViewModels.MyViewModel
And the Action method:
[HttpPost]
public ActionResult Create(MyViewModel myViewModel)
{
}
I am passing a new MyViewModel into the partial view to begin...
public ActionResult Create()
{
MyViewModel model = new MyViewModel();
return PartialView(model);
}
EDIT 2
Ok When I render my partial view that contains the forms I call :
#{Html.RenderAction("Create", "MyController");}
this is called from within a View of type #model IEnumerable<MyApp.Models.MyObject>
(this view displays a list of currently existing MyOjects, and at the bottom the partial is rendered to allow the user to add another MyObject to the DB)
If you are not already doing so, try creating a editor template (e.g., Views->Shared->EditorTemplates) called MyObject.cshtml. Move your partial view content to this view and then call
#Html.Editor("myObject").
from your parent partial view.
Change your ViewModel to have the Description directly
public class MyViewModel
{
public string Description { get; set; }
public List<MyList> myList{ get; set; }
}
then bind accordingly
#Html.EditorFor(x => x.Description);
I would expect the top line of your view to look something like this:
<%# Page Title="" Language="C#" Inherits="System.Web.Mvc.ViewPage<MyViewModel>" %>
This tells the view that the model it is supplied is of type MyViewModel (a la <T> style).
I don't think the out of the box model binding knows how to bind to complex objects. You're probably going to have to write up some sort of custom model binder.
I'm afraid it's not something I've done since MVC1 so I'm a bit hesitant to give you any sample code because the mechanism may well have changed completely since then. A quick google did turn up this article http://www.learnxpress.com/asp-net-mvc-hosting-6-tips-for-asp-net-mvc-model-binding-2.html and this article http://bradwilson.typepad.com/blog/2010/10/service-location-pt9-model-binders.html.
Edit: I've just seen this answer which might help Retrieving data from view, should I use model binder?