I'm a beginner ASP.NET MVC 3 web-developer and have this problem:
There are several view models, that have similar logic and I've come to idea to have one common EditorTemplate for them to be rendered by Html.EditorFor.
The template is named "ExistOrCreateNewInput.cshtml" and is strongly-typed with IExistOrCreateNewInput interface class:
public interface IExistOrCreateNewInput
{
int? existEntId { get; set; }
IUnapprovedNewEntityCreateInput createInput { get; set; }
}
Template's content is something like:
#model IExistOrCreateNewInput
<h2>Add or choose</h2>
#* here put some common js code *#
Html.EditorFor(o => o.existEntId)
Html.EditorFor(o => o.createInput)
Suppose I have some sort of models that implement this interface, for example:
public class FirstModelInput : IExistOrCreateNewInput
{
[Display(Name="First")]
[UIHint("Lookup")]
public int? existEntId {get; set;}
[UIHint("PaperCreateInput")]
public PaperCreateInput paperCreateInput {get; set;}
public IUnapprovedNewEntityCreateInput createInput
{
get
{
return paperCreateInput;
}
set { }
}
}
public class SecondModelInput : IExistOrCreateNewInput
{
[Display(Name="Second")]
[UIHint("Lookup")]
public int? existEntId {get; set;}
[UIHint("ThesisCreateInput")]
public ThesisCreateInput thesisCreateInput {get; set;}
public IUnapprovedNewEntityCreateInput createInput
{
get
{
return thesisCreateInput;
}
set { }
}
}
public class ThirdModelInput : IExistOrCreateNewInput
{
...
}
Where PaperCreateInput and ThesisCreateInput classes implement IUnapprovedNewEntityCreateInput interface.
So, I want my view model
public class SomeGlobalViewModel
{
[Required]
string name {get; set;}
[UIHint("ExistOrCreateNewInput")]
FirstModelInput firstModel {get; set;}
}
to render correctly the attribute "firstModel" with Html.EditorFor(o => o.firstModel) method.
Now I know that EditorFor method is dealing with Metadata, so probably my question should be like "how can I pass metadata of attributes to base interface attributes". Correct me, if I'm wrong.
Anyway, I need those helper methods
Html.EditorFor(o => o.existEntId)
Html.EditorFor(o => o.createInput)
in my editor template (strongly-typed with interface) to render my Models' attributes as I declared them in implementing classes:
[UIHint("Lookup")]
public int? existEntId {get; set;}
[UIHint("PaperCreateInput")]
public PaperCreateInput createInput {get; set;}
Thanks in advance.
Sorry for my bad English.
Related
I'm learning about the Bind attribute and I have a doubt.
I can use the Bind attribute to include/exclude the data that will be posted, so.
Would it not be better to use a specific ViewModel instead of the Bind attribute?
Think about what happened if your entity changes overtime, then you might force to change all your different viewModels which you have created instead of using Include or Exclude. it will get hard to maintain your code.
Suppose you have this :
public class PersonalViewModel
{
private int PersonalID { get; set; }
public string PersonalName { get; set; }
public string PersonalFamily { get; set; }
public byte? GenderID { get; set; }
public string PersonalPhone { get; set;}
}
Consider these :
public string ShowPersonalToAll(
[Bind(Exclude = "PersonalPhone")]PersonalViewModel newPersonal)
{...}
OR
public class PersonalViewModel
{
private int PersonalID { get; set; }
public string PersonalName { get; set; }
public string PersonalFamily { get; set; }
public byte? GenderID { get; set; }
}
Now What if saving personal's mobile become important! and if you have created different customized ViewModel for several action (depends on application's business)?
Then you have to change the main ViewModel and all the other Customize ViewModel, While by using Exclude there is no need to change ViewModels, no need to change actions and the main ViewModel just changes.
I have a ViewModel. something like this
public class ViewModel
{
public int Id { get; set; }
public int? Value { get; set; }
}
I have a table of existing ViewModels, and below that I have a form where you can add a new ViewModel
For existing ViewModels that are fetched from DB i want no validation on the Value property, but for the case when adding a new ViewModel I want required validation.... The real model is more complex then this one so I want to use the same model in both cases.. Is it possible?
edit: this works
public class AddNewViewModel : ViewModel
{
public new int Value { get; set; }
}
Is it better to use new or virtual/override and why?
Required attributes are compiled into the class. You could do something like this:
public class BaseViewModel
{
public int Id { get; set; }
public virtual int? Value { get; set; }
}
public class CreateViewModel : BaseViewModel
{
[Required]
public override int? Value { get; set; }
}
This way, you only add the validation attribute to the properties where you need them.
I have an abstract class
public abstract class Member
{
public string ID { get; set; }
public string Username { get; set; }
public int MemberType { get; set; }
public abstract string MemberName { get; set; }
public int Status { get; set; }
}
public class Person : Member
{
public string LastName { get; set; }
public string FirstName{ get; set; }
}
public class Business : Member
{
public string BusinessName { get; set; }
public string TaxNo { get; set; }
}
The class was mapped using fluent API,
Now, is there a way to update the "Status" property from the view(having Member model) without using or going to a subclass (Person/Business)?
I just tried it, but it says "Cannot create an abstract class.", when submitting the page.
Or there is a correct way to do this?
Thanks
Not in EF. You have to instantiate an object to work with EF, and you can't instantiate an abstract class.
You could make the class not be abstract. Or you could use a stored proc to update the field, or some direct sql.
It sounds like your problem is that your action method has an abstract type as a parameter, which the default model binder can't do anything with. If you are dead set on using the same view for two different classes, you may need to implement your own model binder to inspect in the incoming request and decide which type, Person or Business, to instantiate.
Check out this link for more information on creating a custom model binder:
http://odetocode.com/blogs/scott/archive/2009/05/05/iterating-on-an-asp-net-mvc-model-binder.aspx
This seems like a similar problem to the one I've answered previously here:
ASP.NET MVC 3: DefaultModelBinder with inheritance/polymorphism
I'd like to change the default behavior of .Where method for specific case(s).
All my Business Objects inherit from BaseObject that has property int ID {get; set;}
// Base class
public abstract class BaseObject
{
public abstract int ID {get; set;}
}
I have 2 classes:
public partial class User : BaseObject
{
public override int ID {get; set;}
public string Username { get; set; }
public int ProfileID { get; set; }
public virtual Profile Profile { get; set; }
}
public partial class Profile : BaseObject
{
public override int ID { get; set; }
public string Name { get; set; }
public virtual ICollection<User> Users { get; set; }
public static Profile GetAdminProfile()
{
return new Profile(){ID = 3, Name = "Admin profile"};
}
}
I would like to write
// This throws Unable to create a constant value of type 'Profile'... exception
User admin = Users.Where(user.Profile == Profile.GetAdminProfile()).FirstOrDefault();
instead of
User admin = Users.Where(user.Profile.ID == Profile.GetAdminProfile().ID).FirstOrDefault();
Is there a way to achieve this?
This is a known problem in Entity Framework. You will have follow the second approach.
I am curious to know the best way to approach the following scenario:
public class LittleThingViewModel
{
public string Id{ get; set; }
public string Name { get; set; }
public string Location { get; set; }
}
public class BigThingViewModel
{
public LittleThingViewModel little1 {get; set; }
public LittleThingViewModel little2 {get; set; }
public string propA {get; set; }
public string propB {get; set; }
public string propC {get; set; }
}
In the initial CREATE action of my controller, I populate two LittleThingViewModels, assign them to a new BigThingViewModel and pass it to the strongly-typed view. I then use EditorFor to render edit controls for BigThing properties A, B, and C.
What is the best technique for automatically rendering the LittleThingViewModels to the form such that when I post back to my controller it auto-binds? (My goal is to only display the Name and keep the other properties hidden)
public ActionResult Create(BigThingViewModel b)
I found that I could render A, B, and C properties in addition to each individual property of the two LittleThing sub-viewmodels and it successfully bind BigThingViewModel during POST:
Html.DisplayFor(model=>model.little1.Name)
Html.HiddenFor(model=>model.little1.Name)
Html.HiddenFor(model=>model.little1.Id)
Html.HiddenFor(model=>model.little1.Location)
Is there a technique that would allow me to render both labels and hidden elements automatically instead of having to do them each explicitly each time?
Something like:
Html.RenderFor(model=>model.little1)
Thanks
Create a partial view that is strongly typed to the LittleThingViewModel.
LittleThingView.ascx (partial view)
Html.DisplayFor(model=>model.Name)
Html.HiddenFor(model=>model.Name)
Html.HiddenFor(model=>model.Id)
Html.HiddenFor(model=>model.Location)
In main View
<%
Html.RenderPartial("LittleThingView",model.little1);
Html.RenderPartial("LittleThingView",model.little2);
%>
To make it look better you can make a collection for these objects in the big ViewModel. So if one of them is null or you need more than one, it wouldn't need any changes.
public class BigThingViewModel
{
public List<LittleThingViewModel> littles=new List<LittleThingViewModel>();
public string propA {get; set; }
public string propB {get; set; }
public string propC {get; set; }
}
And in the view:
<%
foreach(var littleThingViewModel in model.littles)
{
Html.RenderPartial("LittleThingView",littleThingViewModel);
}
%>