I am new to MVC (i.e. the last few days) and i would like to know if what i have done is the best way.
I have a view that is a combination of an insert item form with a list details form underneath for a particular entity. As such i kind of need 2 models for the page in order to avoid doing things like #Html.LabelFor(model => model.FirstOrDefault().EventTypeID, "Event Type").
What i have done is set the model to be Tuple<IEnumerable<Event>,Event> that way i have both the single item and the collection of items. Can anyone suggest a less hacky alternative or is this the best way of doing this?
There are 2 solutions.
You should create a different View Model Class (a simple class with both models as properties)
You can assign it to the ViewBag.Model1 ... ViewBag.Model2 ... But this is dynamic so you will have no intellisense and you can get errors at runtime.
You should use a ViewModel like this
public class ViewModel
{
public TypeOfYourModel MyModel1 { get; set; }
public TypeOfYourModel MyModel2 { get; set; }
}
I suggest you create a ViewModel that would contain both objects you want to pass.
public class NewEventViewModel
{
public Event NewEvent { get; set; }
public Event EventDetails { get; set; }
}
You could also use ViewBag, but it is not strongly typed so you would not get IntelliSense.
I would create a Model object just for the view, with 2 properties, one for the single entity and one for the collection, and then you can pass this composed object as the model for the view
Related
I am trying to understand and implement different UI patterns in .NET to see the pros and cons and where they suite best.
I understand the main concept but I was creating an app and a question appeared.
Say we have a class Customer, which represents the core Information of a customer.
public class Customer
{
public int Id { get; set; }
public string Name { get; set; }
public string Address { get; set; }
public string City { get; set; }
public string Country { get; set; }
public string PostalCode { get; set; }
public string PhoneNumber { get; set; }
}
Now, if I create a WebView or WebForm to show all customers I can use this class to set as source f.e. to a DGV, being able to show all properties above.
But then I want to show for example a View/Form with the Revenue history of each customer.
So there is a class CustomerRevenue like
public class CustomerRevenue
{
public Revenue ActualYearExpectedRevenue { get; set; }
public IList<Revenue> RevenuePerYearList { get; set; }
public decimal ActualYearProjectedRevenue => CalculateYearProyection();
public decimal CalculateYearProyection(int year)
{
var daysInYear = DateTime.IsLeapYear(year) ? 365 : 366;
var actualYearRevenue = RevenuePerYearList.SingleOrDefault(x => x.Year == year);
var dayNumber = DateTime.Now.DayOfYear;
var projection = ((actualYearRevenue.Amount * daysInYear) / dayNumber);
return projection;
}
}
Here, to set RevenuePerYearList we need some time, since let's say we sell a lot and have a huge list of sells with huge lists of articles, so the calculation needs some time.
So now my question:
Should I then have "concrete" classes for each view/model with the data I want to show, i.e. here I would have apart of Customer class, say a CustomerRevenueModel
public class CustomerRevenueModel
{
private readonly CustomerRevenue _customerRevenue = new CustomerRevenue();
public int Id { get; set; }
public string Name { get; set; }
public string Address { get; set; }
public string City { get; set; }
public string Country { get; set; }
public string PostalCode { get; set; }
public CustomerRevenue CustomerRevenue
{
get { return _customerRevenue; }
}
}
}
which has (maybe) different properties, so I need to load this "heavy" properties when needed
or
should I stay with only one class (I mean, a customer always has a revenue) and leave the properties "empty"?
The first option makes me have a lot of classes, one for each view/form I want to show data for (maybe being able to reuse some models in various views/forms) but keeps all clean and in a valid state. And also each class can have it's own logic (domain logic - DDD)
The second option is less classes, less code, but some way I end having a huge (God) class, with all the properties a Customer has and all it's logic (methods). I load only the ones I need, but this appears really bad to me.
The third option is to have the big class with all properties and methods as my (domain)model, and create a "ViewModel" (which contains no methods, only props) each time I need to show sth. like above , using it as source for my GridView. This is the solution with more classes and code (big class + ViewModels + (maybe) DTOs), but also the more organized and SOLID design to my eyes... Here the use of a Mapper like AutoMapper would really help, mapping between objects
But this is the part I'm confused about...
Are these "ViewModels" a bad pattern using MVC or MVP?
Are this the same as the VM in MVVM? Which I Think not, since I've understood VM in MVVM like a "template", but what I talk about appears to me more like DAOs??
Or they don't have nothing to do, are just DAOs
I think I am a bit confused about all the different meanings of Model, ViewModel etc, in the different design patterns.
I am hardly trying to understand right MVC,MVP,MVVM and DDD and I think sometimes I am mixing terms...?
First, try to not "mix" things from different patterns, ViewModels are for MVVM, and you NEED ViewModels if you want to implement MVVM (ASP.Net MVC uses something called ViewModels, but it is not the same than the ViewModels in MVVM design pattern)
The ViewModel is like a model for the View. The ViewModel work is to "convert" the Model(s) to something the View can understand.
You can have one o more models (or none) and use it in the ViewModel, you have a ViewModel for each View.
In your example (a datagridview) you can have a model that will represent the data in a datagridview, a DTO if you want, and you can have a property in the ViewModel, a List and you will fill with data loaded from the database. In the View, you will bind that property (the list) to the dgv datasource.
Think that the ViewModel is something like the code behind of the view, but you are working with properties and commands that will be binded to controla in the view.
What's the best way to design a class (or classes) that can hold the potential values of item, as well as the one the user actually selected? I've come across this problem before and always feel like I'm missing a core class design feature.
Right now I usually do something like the following
class MultiChoice
Name (I.e. Box Size)
Default Value ("22x15")
PotentialValues ({"10x10","20x20","22x15"})
But that doesn't handle the actual value the user selected, so I add that in.
class MultiChoice
Name (I.e. Box Size)
Default Value ("22x15")
PotentialValues ({"10x10","20x20","22x15"})
SelectedValue
That doesn't feel right though, because when I construct a drop-down I'm filling in stuff with SelectedValue = null. Then when I store the data, I'm storing all the options too, which I don't need.
Is there a better way to handle this with an interface or other language construct? I always feel like I'm missing something blatantly obvious here.
You really have two separate entities here:
MultiChoiceQuestion
MultiChoiceAnswer
Create two separate classes to represent these two separate concepts.
ASP.NET MVC has the SelectList class. While you might not actually be working in ASP.NET MVC, it seems clear that Microsoft felt that the concept of "backing class for a dropdown" was universal enough to warrant its own class.
In whatever you consider the "Model" (that part of your program containing the business domain classes and business logic), there will always exist database tables that serve as lookups for these dropdowns.
tblCountries
CountryID PK
CountryCode string
FullName string
In your ViewModel, there will be a corresponding list of countries from which you can populate the dropdown:
public class InvoiceViewModel
{
...
public int CountryID { get; set; }
public SelectList Countries { get; set; }
// or
public List<Country> Countries { get; set; }
...
}
Of course, by the time you get to the UI, the actual dropdown contains enough plumbing to hold both the select list and the selected value.
You really only need a single Value field. Set it to whatever you want in the constructor (so it's defaulted when the object is created). You can also change your 'potential values' to be static, so it's the same for the entire class.
public class Box
{
public string Value { get; set; }
public static List<string> AllowedValues { get; private set; }
public Box()
{
AllowedValues.AddRange(new string[]{"10x10","20x20","22x15"});
Value = AllowedValues.First();
}
}
Then when a user changes the value, simply update it.
Box thisBox = new Box();
string val = "22x15";
if (Box.AllowedValues.Contains(val))
thisBox.Value = val;
I am little confuse on the ViewModel design with Inheritance.
Scenaro:
I have a datamodel and multiple viewmodels of User Enity. I am using ADO.Net to fetch from DB bind to datamodel. And the datamodel can be passed to different ViewModel.It seems Ok with one or two views. But When number of my Views increases, I need different ViewModels. Also I want to avoid redundant fields in my ViewModel. And I create a UserBaseModel. So all ViewModel inherit from it
Problem:
I have password and confirm password fields for UserSetting Views and UserRegistration view and I create UserSettingViewModel and UserRegistrationViewModel. And I dont think other viewmodel do not require this fields. I dont want to define the fields in UserBaseModel and also I dont want to define multiple times for the same fields in both ViewModels.
Is there any alternative? Suggestions and advices are welcome
Since C# doesn't support multiple inheritance you can't derive the models from a second base model. You basically end up with creating another base view model which derives from UserBaseModel and contain the password properties:
public UserBaseModelWithPassword : UserBaseModel
{
public string Password { get; set; }
public string PasswordConfirm { get; set; }
}
Then you can derive UserSettingViewModel and UserRegistrationViewModel from it.
Little more thoughts give me another solution.
public PasswordModel
{
public string Password { get; set; }
public string PasswordConfirm { get; set; }
}
public UserSettingViewModel
{
public PasswordModel Password { get; set; }
}
I have a model that stores company information, including tax IDs. In the US, these are 9 digit numbers and are typically displayed as ##-#######. However, in my system, I am storing these as strings with no hyphen - since other countries can have identification numbers that differ in length and format, I don't want be limited to a US standard.
Now I want to program my views to display US tax IDs in their "friendly" format. I have this working right now with a helper method I put in the Company model class:
public string FormatTaxID(string TaxID)
{
if (Address.Country == "United States")
return Regex.Replace(TaxID, #"(\d{2})(\d{7})", "$1-$2");
else
return TaxID;
}
Then in my view, I'm using:
#item.FormatTaxID(item.TaxID)
This all works fine, but it doesn't feel right to store a method like this in the model - it feels like this is more of a view/view model responsibility than a model responsibility, as it is solely for presentation.
I am using view models and thought of putting it there, but I I have multiple view models for the underlying model and don't want to repeat code if I don't have to. Also, my view model for the index uses collections and I'm not sure how I would work the method into it:
public class CompanyIndexViewModel
{
public IEnumerable<Company> Companies { get; set; }
public IEnumerable<Document> Documents { get; set; }
}
How would I apply this method to a collection like that?
Another option is creating a new helper/utility class and sticking it in there. What would MVC convention dictate?
For one-offs, I'd say use the view model. If it's something that you will reuse over and over, move it into a utility class that your views/view models/etc. can reference.
And, there's technically nothing wrong sort of doing it both ways. Put the method in a utility class and then add a property to your view model that returns this, e.g.:
public class CompanyIndexViewModel
{
...
public string TaxID { get; set; }
public string USFormattedTaxID
{
get { return Utilities.FormatTaxID(TaxID); }
}
}
The localized-to-the-Company-context TaxID of the company is properly a property of the Company, and is not a presentation detail.
For example, I have 3 models with an Id (int), a Name (string) and an active (bool). It's possible to use just one view for these models with the same properties ? A technique like a generic object ? Inheritance ? It's to avoid to write multiple views with the same HTML code.
You could create a ViewModel.
For sample:
public class CustomerViewModel
{
public int Id { get; set; }
public string Name { get; set; }
public bool Active { get; set; }
}
And create another ViewModel with a type like this:
public class CustomersViewModel
{
public CustomerViewModel Customer1 { get; set; }
public CustomerViewModel Customer2 { get; set; }
public CustomerViewModel Customer3 { get; set; }
}
and type your view with this type:
#model CustomersViewModel
Or just use an collection to type your view
#model List<CustomerViewModel>
Take a look at this anwser!
https://stackoverflow.com/a/694179/316799
In a view you can either
specify shared base class for all models and use that.
use dynamic as model
split view in shared (extract into separate view) and specific part. Than call shared sub-view with either existing model (if using base class/dynamic) or simply new model constructed based on data in specific model.
Sample of extracting shared portion with inheritance. Using Html.Partial to render shared portion:
class SharedModel { /* Id,...*/ }
class SpecificModel : SharedModel { /* Special... */ }
SpecificView:
#model SpecificModel
#Html.Partial("SharedView", Model)
<div>#Model.Special</div>
SharedView:
#model SharedModel
<div>#Model.Id</div>
Side note: You can specify view name when returning result by using View if view name does not match action name:
return View("MySharedView", model);
In ASP.NET MVC4 you have the opportunity not to define a model for the view. This means leave the definition of the model empty (don't use #model MyNamespace.MyClass) and then it will automatically use "dynamic" as model.
Greetings
Christian