I have 1 project name MVC1
I have 2 classes below:
public class category
{
public int ID {get;set;}
public string Name {get;set;}
}
public class detail
{
public int Id {get;set;}
public string Name {get;set;}
public int CategoryID{get;set;}
}
and 2 Intefaces
public inteface ICategory
{
IList<category> ListCategory();
}
public interface IDetail
{
IList<Detail> ListDetail();
}
and 1 Model RCateory inheritance from inteface ICategory
public IList<Category> FindAllCategory()
{
List<Category> Listcategory_ = new List<Category>();
foreach (var category in Listcategory)
{
Listcategory_.Add(category);
}
return Listcategory_;
}
and 1 Model name RDetail inheritance from inteface IDetail
public IList<Detail> FindAllDetail()
{
List<Detail> Listdetail_ = new List<Detail>();
foreach (var detail in Listdetail_)
{
Listdetail_.Add(detail);
}
return Listdetail_;
}
and 1 Controller
DetailController
private RDetail rDetail = new RDetail();
private RCategory rCategory = new RCategory();
public ActionResult ListDetail()
{
var detail = rdDetail;
return View("CreateDetail");
}
and 1 View type (cshtml) CreateDetail container
#model MVC1.Detail
How do I put into the category to #Html.DropDownListFor
As always in an ASP.NET MVC application you start by creating a view model class that will contain everything that your view needs:
public class MyViewModel
{
public Detail Detail { get; set; }
public IEnumerable<SelectListItem> Categories { get; set; }
}
and then have your controller action populate and pass this view model to the view:
public ActionResult ListDetail()
{
var model = new MyViewModel();
model.Detail = rDetail;
model.Categories = FindAllCategory().Select(x =>
Value = x.ID.ToString(),
Text = x.Name
);
return View("CreateDetail", model);
}
and finally your view will become strongly typed to the view model and you will be able to display the dropdown:
#model MyViewModel
...
#Html.DropDownListFor(x => x.Detail.CategoryID, Model.Categories)
Related
I am just learning MVC. Here's What I have tried so far:
public class StoreXml
{
public string StoreCode { get; set; }
public static IQueryable<StoreXml> GetStores()
{
return new List<StoreXml>
{
new StoreXml { StoreCode = "0991"},
new StoreXml { StoreCode = "0015"},
new StoreXml { StoreCode = "0018"}
}.AsQueryable();
}
In Controller:
public SelectList GetStoreSelectList()
{
var Store = StoreXml.GetStores();
return new SelectList(Store.ToArray(),"StoreCode");
}
public ActionResult IndexDDL()
{
ViewBag.Store = GetStoreSelectList();
return View();
}
In View:
#Html.DropDownList("store", ViewBag.Stores as SelectList, "Select a Store")
What am I doing wrong here? Dropdown shows Cie_Mvc.Models.StoreXml only but no values. Please suggest.
You're storing it in ViewBag.Store and calling it in the View, ViewBag.Stores
public ActionResult IndexDDL()
{
ViewBag.Stores = GetStoreSelectList();
return View();
}
#Html.DropDownList("store", ViewBag.Stores as SelectList, "Select a Store")
As a side note, this is the issue with using a dynamic object. I would suggest putting the property in a ViewModel, so you get intellisense.
I would do it differently. I would separate my class from my list of the classes like:
public class StoreXml
{
public string StoreCode { get; set; }
}
Then I would use something like a repository to get some data, even if it is hard coded, or you can just populate a list from your controller. Always use a view model to represent your data on the view:
public class MyViewModel
{
public string StoreXmlCode { get; set; }
public IEnumerable<StoreXml> Stores { get; set; }
}
And then your controller can look something like this:
public class MyController
{
public ActionResult MyActionMethod()
{
MyViewModel viewModel = new MyViewModel();
viewModel.Stores = GetStores();
return View(viewModel);
}
private List<StoreXml> GetStores()
{
List<StoreXml> stores = new List<StoreXml>();
stores.Add(new StoreXml { StoreCode = "0991"});
stores.Add(new StoreXml { StoreCode = "0015"});
stores.Add(new StoreXml { StoreCode = "0018"});
return stores;
}
}
And then your view could look something like this:
#model MyProject.ViewModels.Stores.MyViewModel
#Html.DropDownListFor(
x => x.StoreXmlCode,
new SelectList(Model.Stores, "StoreCode", "StoreCode", Model.StoreXmlCode),
"-- Select --"
)
I hope this can lead you in the right direction :)
Could I have more models on a razor page?
for example when I have more grid controls each with an area(a template) for editing the data,and after that i want to save the data and see it in the grid.
You can do something like the example below (this is a very over simplified example):
public class AnimalDataViewModel
{
public List<Dog> DogData { get; set; }
public List<Cat> CatData { get; set; }
public List<Mouse> MouseData { get; set; }
public AnimalDataViewModel()
{
this.DogData = new List<Dog>();
this.CatData = new List<Cat>();
this.MouseData = new List<Mouse>();
}
}
Then in your action method:
public ActionResult DisplayAnimalDataGrids()
{
AnimalDataViewModel model = new AnimalDataViewModel();
model.DogData = this.myDataService.GetDogData();
model.CatData = this.myDataService.GetCatData();
model.MouseData = this.myDataService.GetMouseData();
return View(model);
}
Then in your view:
#model AnimalDataViewModel
#Html.Grid(Model.DogData)
#Html.Grid(Model.CatData)
#Html.Grid(Model.MouseData)
I've tried to follow a few examples from here and a couple other resources to just create a very simple member in my viewmodel and display it as a dropdown list on my view with a dropdownlistfor() helper. I can't seem to wrap my head around it and it's not working with what I'm trying.
here's my viewmodel:
public class Car
{
public int CarId { get; set; }
public string Name { get; set; }
}
public class MyViewModel
{
public IEnumerable<Car> Cars = new List<Car> {
new Car {
CarId = 1,
Name = "Volvo"
},
new Car {
CarId = 2,
Name = "Subaru"
}
};
public int MyCarId { get; set; }
}
and here is my view:
#Html.DropDownListFor(m => m.MyCarId, new SelectList(Model.Cars, "CarId", "Name"))
and here is my controller:
public ActionResult MyView()
{
return View();
}
You need to make sure you send the Model to your View:
public ActionResult Index()
{
var myViewModel = new MyViewModel()
return View(myViewModel);
}
And in your View you need to make sure you're defining your Model:
#model namespace.MyViewModel
You example works fine, I think you forgot to send MyViewModel in POST Action.
[HttpPost]
public ActionResult Index(MyViewModel model)
{
return View(model);
}
I am trying to create a dropdown list to display all the value in a custom collection class
such as
public class MyCustomClassCollection
{
public List<MyCustomClass> {get;set;}
}
I want it to show the Description:string of each MyCustomClass
I tried
<%: Html.DropDownList "Description", MyCustomClass %>
Resharper suggests that I cast MyCustomClass to IEnemerable
but the server returns an unable to cast error.
Any Idea how I can create this DropDownList?
__Modification___
public class ViewModel
{
public Detail detail { get; set; }
}
public class Detail //Inherited from webservce
{
public CustomClassCollection {get;set;}
.... Other Properties, a.k.a Custom Classes
}
public class CustomClassCollection
{
public List<CustomClass> {get;set;}
}
public class CustomClass {
public int Id {get;set;}
public string Description{get;set;}
... other properties
}
public ActionResult Index(int? id, DateTime? date)
{
if (id.Equals(null))
id = ######### ;
if (date.Equals(null))
date = DateTime.Today;
var vm = new ViewModel
{
Detail = _repository.Detail((int)id,(DateTime)date)
};
return View(vm);
}
The second argument of the DropDownList helper must be an IEnumerable<SelectListItem> or a SelectList which implements this interface for that matter. So in your controller action organize in such a way that you convert your custom collection into an IEnumerable<SelectListItem>. As always you could start by writing a view model:
public class MyViewModel
{
public string SelectedDescription { get; set; }
public SelectList Descriptions { get; set; }
}
and then have your controller action query the custom list and populate the view model which will be passed to the view:
public ActionResult Index()
{
var descriptions = yourCustomCollection.MyCustomClass.Select(x => new
{
Value = x.Description,
Text = x.Description
});
var model = new MyViewModel
{
Descriptions = new SelectList(descriptions, "Value", "Text")
};
return View(model);
}
and finally in your strongly typed view:
<%= Html.DropDownListFor(x => x.SelectedDescription, Model.Decriptions) %>
UPDATE:
After posting your updated models (which by the way are still incomplete and impossible to compile as you haven't provided any property names), here's an example:
public class ViewModel
{
public int SelectedId { get; set; }
public Detail Detail { get; set; }
}
public class Detail
{
public CustomClassCollection MyCollection { get; set; }
}
public class CustomClassCollection
{
public List<CustomClass> CustomClass { get; set; }
}
public class CustomClass
{
public int Id { get; set; }
public string Description { get; set; }
}
public class HomeController : Controller
{
public ActionResult Index()
{
var vm = new ViewModel
{
Detail = new Detail
{
MyCollection = new CustomClassCollection
{
CustomClass = new List<CustomClass>
{
new CustomClass
{
Id = 1,
Description = "description 1",
},
new CustomClass
{
Id = 2,
Description = "description 2",
},
new CustomClass
{
Id = 3,
Description = "description 3",
},
}
}
}
};
return View(vm);
}
}
and in the view:
<%= Html.DropDownListFor(
x => x.SelectedId,
new SelectList(Model.Detail.MyCollection.CustomClass, "Id", "Description")
) %>
What you have to understand in order to define a dropdown list in ASP.NET MVC ius that you need 2 things:
A scalar property to bind the selected value to (SelectedId in my example)
A collection to bind the list to (Model.Detail.MyCollection.CustomClass in the example)
I have a model like so:
return new MyViewModel()
{
Name = "My View Model",
Modules = new IRequireConfig[]
{
new FundraisingModule()
{
Name = "Fundraising Module",
GeneralMessage = "Thanks for fundraising"
},
new DonationModule()
{
Name = "Donation Module",
MinDonationAmount = 50
}
}
};
The IRequireConfig interface exposes a DataEditor string property that the view uses to pass to #Html.EditorFor like so:
#foreach (var module in Model.Modules)
{
<div>
#Html.EditorFor(i => module, #module.DataEditor, #module.DataEditor) //the second #module.DataEditor is used to prefix the editor fields
</div>
}
When I post this back to my controller TryUpdateModel leaves the Modules property null. Which is pretty much expected since I wouldnt expect it to know which concrete class to deserialize to.
Since I have the original model still available when the post comes in I can loop over the Modules and get their Type using .GetType(). It seems like at this point I have enough information to have TryUpdateModel try to deserialize the model, but the problem is that it uses a generic type inference to drive the deserializer so it does not actually update any of the properties except the ones defined in the interface.
How can I get update my Modules array with their new values?
If any particular point isnt clear please let me know and I will try to clarify
You could use a custom model binder. Assuming you have the following models:
public interface IRequireConfig
{
string Name { get; set; }
}
public class FundraisingModule : IRequireConfig
{
public string Name { get; set; }
public string GeneralMessage { get; set; }
}
public class DonationModule : IRequireConfig
{
public string Name { get; set; }
public decimal MinDonationAmount { get; set; }
}
public class MyViewModel
{
public string Name { get; set; }
public IRequireConfig[] Modules { get; set; }
}
Controller:
public class HomeController : Controller
{
public ActionResult Index()
{
var model = new MyViewModel
{
Name = "My View Model",
Modules = new IRequireConfig[]
{
new FundraisingModule()
{
Name = "Fundraising Module",
GeneralMessage = "Thanks for fundraising"
},
new DonationModule()
{
Name = "Donation Module",
MinDonationAmount = 50
}
}
};
return View(model);
}
[HttpPost]
public ActionResult Index(MyViewModel model)
{
return View(model);
}
}
View:
#model MyViewModel
#using (Html.BeginForm())
{
#Html.EditorFor(x => x.Name)
for (int i = 0; i < Model.Modules.Length; i++)
{
#Html.Hidden("Modules[" + i + "].Type", Model.Modules[i].GetType())
#Html.EditorFor(x => x.Modules[i])
}
<input type="submit" value="OK" />
}
and finally the custom model binder:
public class RequireConfigModelBinder : DefaultModelBinder
{
protected override object CreateModel(ControllerContext controllerContext, ModelBindingContext bindingContext, Type modelType)
{
var typeParam = bindingContext.ValueProvider.GetValue(bindingContext.ModelName + ".Type");
if (typeParam == null)
{
throw new Exception("Concrete type not specified");
}
var concreteType = Type.GetType(typeParam.AttemptedValue, true);
var concreteInstance = Activator.CreateInstance(concreteType);
bindingContext.ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(() => concreteInstance, concreteType);
return concreteInstance;
}
}
which you would register in Application_Start:
ModelBinders.Binders.Add(typeof(IRequireConfig), new RequireConfigModelBinder());
Now when the form is submitted the Type will be sent and the model binder will be able to instantiate the proper implementation.