I am considerably new to MVVM implementation. This might sound like a repetitive question but there is nothing that I could find that would help me understand better with my knowledge which is basic. I have a Model class with members as shown here:
public class Model
{
public string Name { get; set; }
public int Age { get; set; }
public List<Model> Children { get; set; }
}
I have wrapped this model class in a view model but with ObservableCollection in place of List.
public class ViewModel
{
private Model model;
public ViewModel()
{
model = new Model();
}
//getters and setters for both Name and Age
public ObservableCollection<ViewModel> Children
{
//how to convert List<Model> to ObservableCollection<ViewModel> here?
}
}
I definitely do not want to expose my Model class to the view which is why I need to create an ObservableCollection of the VM class. Not sure how to achieve this though. Any help appreciated.
You are probably looking for the following:
public class Model
{
public string Name { get; set; }
public int Age { get; set; }
public List<Model> Children { get; set; }
}
public class ViewModel
{
public ViewModel(Model m)
{
Name = m.Name;
Age = m.Age;
Children = new ObservableCollection<ViewModel>(m.Children.Select(md=>new ViewModel(md)));
}
public string Name { get; set; }
public int Age { get; set; }
public ObservableCollection<ViewModel> Children { get; set; }
public Model GetModel()
{
return new Model()
{
Age = Age,
Name = Name,
Children = Children.Select(vm=>vm.GetModel()).ToList(),
};
}
}
You will note that a lot of that is boilerplate code. But if you do it this way, your model/viewmodel are completely separated, which will save you SO many problems down the line.
Related
I have a model which is storing mycustomer new request information.
In another history model i am storing all previous request of the customer.
In view i would like to take new order and also see his previous orders and suggest some food after seeing his previous order.
Here are my models...
public class CustomerFoodModel
{
public DateTime FoodRequestCreated { get; set; }
public string FoodRequestType { get; set; }
...
...
}
public class CustomerHistoryModel
{
public string Name { get; set; }
public DateTime FoodRequestCreated { get; set; }
public string FoodRequestType { get; set; }
...
...
}
Helper.cs file
public static CustomerFoodModel getCustomerDetails(int id) // id is loyalty card number
{
// get details from (cutomer) sql table
//store it in (CustomerFoodModel)
// check if it has previous orders
getCustomerHistoryDetails(id);
....
}
public static CustomerHistoryModel getCustomerHistoryDetails(int id)
{
// get deails from (history) sql table
// store it in (CustomerHistoryModel
}
In my controller, I am passing my (CustomerFoodModel) to the view.
public ActionResult EditCustomerRequest(int id, string name, string date)
{
CustomerFoodModel CRequest = Helper.getCustomerDetails(id);
...
return PartialView("EditCustomerRequest",CRequest);
}
How do I show the (CustomerHistoryModel) in the same view.? Is there possible to include (CustomerHistoryModel) in (CustomerFoodModel)?
Create a new class to wrap both of the model.
public class CustomerFoodModel
{
public CustomerFoodModel CustomerFood { get; set; }
public CustomerHistoryModel CustomerHistory { get; set; }
}
And on your controller
public ActionResult EditCustomerRequest(int id, string name, string date)
{
CustomerFoodModel CRequest = Helper.getCustomerDetails(id);
CustomerHistoryModel CHModel = Helper. getCustomerHistoryDetails(id);
return PartialView("EditCustomerRequest",new CustomerFoodModel(){
CustomerFood = CRequest,
CustomerHistory = CHModel
});
}
I think the best approach is to use a partial view inside the main view. The partial view can call back to another controller to get a new model and pass that model to the partial view. This keeps things better seperated.
Look at this post for a similar issue.
Using partial views in ASP.net MVC 4
Use wrapper class which contain both of class
public class CustomerViewModel
{
public CustomerFoodModel FoodModel { get; set; }
public CustomerHistoryModel HistoryModel { get; set; }
}
You have a few options. I would probably could create a view model that contains both of your models:
public class CustomerViewModel
{
public CustomerFoodModel FoodModel { get; set; }
public CustomerHistoryModel HistoryModel { get; set; }
}
Or, depending on your data structure, you may have multiple history entries per customer:
public class CustomerViewModel
{
public CustomerFoodModel FoodModel { get; set; }
public List<CustomerHistoryModel> HistoryModels { get; set; }
}
Then your getCustomerDetails function would return a CustomerViewModel instead.
I want to group my list by a related tables property name lightType. So I tried the PropertyGroupDescription "RelatedPhantoms[0].lightType.Name" but it does not seem to find the property. How can I fix this?
ICollectionView view = CollectionViewSource.GetDefaultView(MainLightList.ItemsSource);
view.SortDescriptions.Add(new SortDescription("RelatedPhantoms[0].lightType.Name", ListSortDirection.Ascending));
view.SortDescriptions.Add(new SortDescription("lightSeries.Name", ListSortDirection.Ascending));
view.GroupDescriptions.Add(new PropertyGroupDescription("RelatedPhantoms[0].lightType.Name"));
view.GroupDescriptions.Add(new PropertyGroupDescription("lightSeries.Name"));
the following is the data backing this collection of lights
public class LightHead : CoreEntity
{
public LightHead()
{
this.RelatedPhantoms = new List<LightHead>();
this.OtherRelatedPhantoms = new List<LightHead>();
}
public LightSeries lightSeries { get; set; }
public Nullable<int> LightSeriesId { get; set; }
public virtual ICollection<LightHead> RelatedPhantoms { get; set; }
public virtual ICollection<LightHead> OtherRelatedPhantoms { get; set; }
}
}
public class LightSeries: CoreModelEntity
{
public string Name { get; set; }
public ICollection<LightHead> lightHeads { get; set; }
public LightType lightType { get; set; }
public Nullable<int> LightTypeId { get; set; }
public LightSeries() { }
public LightSeries(string name)
{
this.Name = name;
}
}
RelatedPhantoms is a collection of LightHead and lightType is a property of LightSeries
so "RelatedPhantoms[0].lightType.Name" may not work
as LightHead class contains lightSeries property of type LightSeries which has the property lightType
so you may change the property description to
"RelatedPhantoms[0].lightSeries.lightType.Name"
above is based on some assumptions after looking the posted code. you may adjust the same as needed.
it is also worth to verify that the collection RelatedPhantoms is of type IList<T> to support indexers
also verify that if RelatedPhantoms collection is supposed to be of Type LightHead or LightSeries as a lightHeads collection in LightSeries do exists, which make me think of relation between these classes
I have a C# MVC Model as follows;
public class MyModel
{
...
public IEnumerable<MyModel> allDetails { get; set; }
public int age { set; get; }
public string gender { set; get; }
public int schoolid { set; get; }
...
}
Now want to retrieve data from allDetails. How can i do it ?
In the controller;
model.allDetails = MyDetails.getAllDetails(); // Saves all details in the Model
Now how can i retrieve age, gender and school from this model; My approach as follows (but its doesn't work)
model.allDetails.age; // This doesn't work
In your code model.allDetails is a list (or smth else that implements IEnumerable), so you have to use foreach or another loop, or just First() to get first value from it: model.allDetails.First().age
I think you got your desing for class MyModel wrong, You should probably have two classes like:
public class MyClass
{
...
public IEnumerable<MyModel> allDetails { get; set; }
public int age { set; get; }
public string gender { set; get; }
public int schoolid { set; get; }
...
}
public class MyModel
{
...
public IEnumerable<MyClass> allDetails { get; set; }
...
}
Where your MyModel class will contain an IEnumerable of your other class which contains properties. Later you can fill your model through controller.
In your current MyModel class, you are keeping IEnumerable of the class itself, so each object for that class will have another IEnumerable and so on.
You may also see: C# Coding Conventions (C# Programming Guide) for your properties names.
My task is to show multiple models into a single view.I've created a ViewModel for my requirement but I'm not meeting my requirement.
please have a look into the below code and rectify me where m i going wrong ???
public partial class StudentsDetail
{
public int StudentID { get; set; }
public int ParentID { get; set; }
public string StudentName { get; set; }
public string Gender { get; set; }
public string FatherName { get; set; }
public string MotherName { get; set; }
public Nullable<System.DateTime> DateOfBirth { get; set; }
public virtual ParentsDetail ParentsDetail { get; set; }
public virtual SchoolDetail SchoolDetail { get; set; }
}
//Model 2
public partial class ParentsDetail
{
public ParentsDetail()
{
this.StudentsDetails = new HashSet<StudentsDetail>();
}
public int ParentID { get; set; }
public string Occupation { get; set; }
public string Organization { get; set; }
public string AnnualIncome { get; set; }
public virtual ICollection<StudentsDetail> StudentsDetails { get; set; }
}
//ViewModel Which I have created
public class ParentsInformationViewModel
{
public List<StudentsDetail> StudentsDetails { get; set; }
public List<ParentsDetail> ParentsDetails { get; set; }
public ParentsInformationViewModel(List<StudentsDetail> _studentDetails, List<ParentsDetail> _parentsDetails) //Should i pass all the required parameters that i want to display in view ????
{
StudentsDetails = _studentDetails;
ParentsDetails = _parentsDetails;
}
//And finally this is my method defined in the StudentController (Have i defined it in a right place/way??)
public ActionResult StudentViewModel()
{
ViewBag.ParentsDetail = new ParentsDetail(); //ParentsDetail is my controller
List<StudentsDetail> studentListObj = StudentsDetailsDAL.GetStudentDetails();
List<ParentsInformationViewModel> ParentInfoVMObj = new List<ParentsInformationViewModel>();
//foreach (var student in studentListObj)
//{
// ParentInfoVMObj.Add(new ParentsInformationViewModel(student.StudentID, student.ParentID));
//}
//ParentInfoVMObj.Add(ParentInfoVMObj); /// don't know how to call the required viewmodel
return View(ParentInfoVMObj);
}
I know that the above method of a ViewModel is wrong but how to use it or where am i going wrong I can't get.
I want to display the ViewModel in the view as a detailed view .
Please, correct me as I'm a starter in MVC3 .
Thanks In Advance!!
In your controller, define your action method as follows.
public ActionResult ParentsDetails()
{
var studentDetails = new List<StudentDetail>();
var parentDetails = new List<ParentsDetail>();
// Fill your lists here, and pass them to viewmodel constructor.
var viewModel = new ParentsInformationViewModel(studentDetails, parentDetails)
// Return your viewmodel to corresponding view.
return View(viewModel);
}
In your view define your model.
#model MySolution.ViewModels.ParentsInformationViewModel
Is there in your view declared that you are receiving model of type
In view:
#model IEnumerable<ParentsInformationViewModel>
I was wondering if it is possible to map multiple DTO objects to a single ViewModel object using Automapper?
Essentially, I have multiple DTO objects and would like to display information from each on a single screen in ASP.NET MVC 2.0. To do so I would like to flatten the DTO objects (or parts of them...) into the Viewmodel and pass said viewmodel to the view. If I had one DTO this would be easy, but I've never seen it being done with multiple. Obviously there are a number of roundabout ways to do this (outside of automapper), but this is the approach that I would like to take if possible.
Check for following link regarding your query
http://consultingblogs.emc.com/owainwragg/archive/2010/12/22/automapper-mapping-from-multiple-objects.aspx
You could create a composite DTO that holds two or more DTO objects and map the composite DTO to the output view model.
If you have 2 DTO classes and 1 flattened view model:
public class Dto1
{
public string Property1 { get; set; }
}
public class Dto2
{
public string Property2 { get; set; }
}
public class FlattenedViewModel
{
public string Property1 { get; set; }
public string Property2 { get; set; }
}
And you create mappings for both DTOs to view model:
CreateMap<Dto1, FlattenedViewModel>();
CreateMap<Dto2, FlattenedViewModel>();
You can map 1st DTO to the model and then just "append" 2nd DTO:
var dto1 = new Dto1 { Property1 = "Value1"; }
var dto2 = new Dto2 { Property2 = "Value2"; }
var model = Mapper.Map<FlattenedViewModel>(dto1); // map dto1 properties
Mapper.Map(dto2, model); // append dto2 properties
You can add a Map override extension method off IMappingEngine that takes a params array. Something like:
public static class AutoMapperExtensions
{
public static T Map<T>(this IMappingEngine engine, params object[] sources) where T : class
{
if (sources == null || sources.Length == 0)
return default(T);
var destinationType = typeof (T);
var result = engine.Map(sources[0], sources[0].GetType(), destinationType) as T;
for (int i = 1; i < sources.Length; i++)
{
engine.Map(sources[i], result, sources[i].GetType(), destinationType);
}
return result;
}
}
You could then call it like this:
var result = Mapper.Engine.Map<MyViewModel>(dto1, dto2, dto3);
This is the information from the expired link in this answer: https://stackoverflow.com/a/8923063/2005596
When using AutoMapper (http://automapper.codeplex.com ) I often have a scenario where I need to map several entities into one entity. Commonly this occurs when mapping from a number domain entities into a single view model (ASP.NET MVC). Unfortunately the AutoMapper API does not expose functionality to map several entities into one entity; however it is relatively simple to create some helper method to do this. Below I will illustrate the approach that I have taken.
In this example I have the following entities in my domain model
public class Person
{
public int Id { get; set; }
public string Firstname { get; set; }
public string Surname { get; set; }
}
public class Address
{
public int Id { get; set; }
public string AddressLine1 { get; set; }
public string AddressLine2 { get; set; }
public string Country { get; set; }
}
public class Comment
{
public string Text { get; set; }
public DateTime Created { get; set; }
}
In addition to this I have a requirement to render the person details the person’s address and any related comment on a single page (using ASP.NET MVC). To implement this I have created the view model shown below, which includes data from all three of the domain entities shown above
public class PersonViewModel
{
public int Id { get; set; }
[DisplayName("Firstname")]
public string Firstname { get; set; }
[DisplayName("Surname")]
public string Surname { get; set; }
[DisplayName("Address Line 1")]
public string AddressLine1 { get; set; }
[DisplayName("Address Line 2")]
public string AddressLine2 { get; set; }
[DisplayName("Country Of Residence")]
public string Country { get; set; }
[DisplayName("Admin Comment")]
public string Comment { get; set; }
}
In the controller action method I make three separate calls into the domain layer to retrieve the required entities but this still leaves the issue that I need to map several source entities onto a single destination entity. To perform this mapping I created a helper class which encapsulates AutoMapper and exposes functionality which enables the mapping of several source objects onto one destination object. This class is shown below
public static class EntityMapper
{
public static T Map<T>(params object[] sources) where T : class
{
if (!sources.Any())
{
return default(T);
}
var initialSource = sources[0];
var mappingResult = Map<T>(initialSource);
// Now map the remaining source objects
if (sources.Count() > 1)
{
Map(mappingResult, sources.Skip(1).ToArray());
}
return mappingResult;
}
private static void Map(object destination, params object[] sources)
{
if (!sources.Any())
{
return;
}
var destinationType = destination.GetType();
foreach (var source in sources)
{
var sourceType = source.GetType();
Mapper.Map(source, destination, sourceType, destinationType);
}
}
private static T Map<T>(object source) where T : class
{
var destinationType = typeof(T);
var sourceType = source.GetType();
var mappingResult = Mapper.Map(source, sourceType, destinationType);
return mappingResult as T;
}
}
To map several source objects onto one destination I have made use of the functionality provided by AutoMapper which allows you to perform a mapping between a source object and a destination object that already exists.
Finally below is the code from the controller that retrieves the three entities and performs the mapping onto a single view model
public ActionResult Index()
{
// Retrieve the person, address and comment entities and
// map them on to a person view model entity
var personId = 23;
var person = _personTasks.GetPerson(personId);
var address = _personTasks.GetAddress(personId);
var comment = _personTasks.GetComment(personId);
var personViewModel = EntityMapper.Map<PersonViewModel>(person, address, comment);
return this.View(personViewModel);
}
I just worked this out myself and have a great solution. It is most likely that your two views are actually related somehow in your system (especially if you are using Entity Framework). Check your models and you should see something which displays the relationship, if you don't then just add it. (The virtual)
Your models
public class Dto1
{
public int id { get; set; }
public string Property2 { get; set; }
public string Property3 { get; set; }
public string Property4 { get; set; }
public string Property5 { get; set; }
public virtual Dto2 dto2{ get; set; }
}
public class Dto2
{
public int id { get; set; }
public string PropertyB { get; set; }
public string PropertyC { get; set; }
public string PropertyD { get; set; }
public string PropertyE { get; set; }
}
Your ViewModels
public class Dto1ViewModel
{
public string Property1 { get; set; }
public string Property2 { get; set; }
public virtual Dto2VMForDto1 dto2{ get; set; }
}
//Special ViewModel just for sliding into the above
public class Dto2VMForDto1
{
public int id { get; set; }
public string PropertyB { get; set; }
public string PropertyC { get; set; }
}
Automapper looks like this:
cfg.CreateMap< Dto1, Dto1ViewModel>();
cfg.CreateMap< Dto2, Dto2VMForDto1 >();
I'm assuming you are getting your data with LinQ:
Dto1ViewModel thePageVM = (from entry in context.Dto1 where...).ProjectTo<Dto1ViewModel>();
Viola, everything will work. In your view just access by using model.dto2.PropertyB