Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use UIHint attribute for property type of interface?

I have the next view model:

public class PickUpLocationViewModel 
{
    public DateTime PuDate {get;set}

    public IAddressViewModel {get;set;}
}

Depends on implementation of IAddressViewModel I want to use appropriate UIHint("Airport"), UIHint("Seaport") etc.. Is it possible? If yes, how?

like image 966
Yara Avatar asked Aug 21 '12 14:08

Yara


2 Answers

You could create an extra property on the IAddressViewModel of TemplateName like so:

public interface IAddressViewModel
{
    string TemplateName { get; }
}

So then for each class that implements IAddressViewModel you can define a separate template name like:

public class SeaportAddressViewModel : IAddressViewModel
{
    public string TemplateName
    {
        get
        {
            return "Seaport";
        }
    }
}

Then in your view you can use one of the overloads of EditorFor like:

@Html.EditorFor(m => m.Address, Model.Address.TemplateName)

This should cause it to use the editor template called Seaport.cshtml.

like image 174
Ian Routledge Avatar answered Nov 15 '22 10:11

Ian Routledge


Let's suppose that you have the following models:

public class PickUpLocationViewModel 
{
    public DateTime PuDate { get; set }

    public IAddressViewModel Address { get; set; }
}

public class AirportAddressViewModel: IAddressViewModel
{
    public string Terminal { get; set; }
}

public class SeaportAddressViewModel: IAddressViewModel
{
    public int DockNumber { get; set; }
}

and then a controller action:

public ActionResult Index() 
{
    var model = new PickUpLocationViewModel 
    {
        Address = new AirportAddressViewModel { Terminal = "North" }
    };
    return View(model);
}

and a corresponding view:

@model PickUpLocationViewModel
@Html.DisplayFor(x => x.Address)

Now you could define the corresponding display/editor templates:

~/Views/Shared/EditorTemplates/AirportAddressViewModel.cshtml:

@model AirportAddressViewModel
@Html.DisplayFor(x => x.Terminal)

~/Views/Shared/EditorTemplates/SeaportAddressViewModel.cshtml:

@model SeaportAddressViewModel
@Html.DisplayFor(x => x.DockNumber)

Now based on the concrete type, ASP.NET MVC will automatically use the correct template.

And when it comes to binding back you will need a custom model binder. I have illustrated one here: https://stackoverflow.com/a/6485552/29407

like image 24
Darin Dimitrov Avatar answered Nov 15 '22 09:11

Darin Dimitrov