2

I've currently got all of this mess at the top of my ViewModels which I feel violates the purpose of a DTO. For example, this is in the constructor of one of my view models -

        Dictionary<int, string> chargeGroups = new Dictionary<int, string>();
        chargeGroups.Add(1, "Administration");
        chargeGroups.Add(2, "Annual Leave");
        chargeGroups.Add(3, "Bereavement");
        chargeGroups.Add(4, "Customer Installation, Setup & Training");
        chargeGroups.Add(5, "Customer Support");
        chargeGroups.Add(6, "Internal Training & Education");
        chargeGroups.Add(7, "Sales & Marketing");
        chargeGroups.Add(8, "Sick");
        chargeGroups.Add(9, "Software Devel / Maint / Test");
        chargeGroups.Add(10, "Software Upgrade / Patch");
        chargeGroups.Add(11, "Other");
        chargeGroups.Add(12, "Other Absence");
        chargeGroups.Add(13, "Warranty");
        chargeGroups.Add(14, "Public Holiday");
        chargeGroups.Add(15, "Other Paid Leave");

        ChargeGroups = new SelectList(chargeGroups, "Key", "Value");

My viewmodel:

    [DisplayName("Charge group")]
    public short? ChargeGroup { get; set; }

    public SelectList ChargeGroups;

then in my view:

            <div class="editor-label">
                @Html.LabelFor(model => model.ChargeGroup)
            </div>
            <div class="editor-field">
                @Html.DropDownListFor(model => model.ChargeGroup, Model.ChargeGroups)
                @Html.ValidationMessageFor(model => model.ChargeGroup)
            </div>

Where should I be putting this stuff?

NoPyGod
  • 4,905
  • 3
  • 44
  • 72
  • 1
    Well since this is a ViewModel and not a Model I don't see an issue here. This has to do with rendering a view so it makes sense to be in a ViewModel. On postback I would transform this into a Model before sending to the database so you are not violating the DTO... Anyways, I am interested in other people's opinions on this. – John Kalberer Jan 11 '12 at 19:30
  • I agree with @JohnKalberer. A ViewModel doesn't have to be a completely anemic DTO, it can contain logic relevant to the View. I would have logic in (or used by) the controller to transform incoming ViewModel data to the Model business layer, and back to outgoing ViewModel data. (One side note: Why is there a `SelectList` on the business model? Isn't `SelectList` specifically an MVC UI element? Business models shouldn't be tightly coupled with a UI implementation.) – David Jan 11 '12 at 19:35
  • I meant to say ViewModel not model sorry. [post edited] – NoPyGod Jan 11 '12 at 20:23

5 Answers5

5

When I have a list of values that wont change I usualy use an Enum and then use a custom Html Helper to render out a select list. You can customzie the display text of the enum values by using meta data description markup.

That way you can just use:

 <%: Html.EnumDropDownListFor(model => model.EnuProperty) %>

or

 @Html.EnumDropDownListFor(model => model.EnuProperty)

Check out this post by Simon which allows you to use the Meta Description attribute to customzie the output for Enum names:

How do you create a dropdownlist from an enum in ASP.NET MVC?

Here is another example but it lacks the meta description property:

http://blogs.msdn.com/b/stuartleeks/archive/2010/05/21/asp-net-mvc-creating-a-dropdownlist-helper-for-enums.aspx

EDIT

Your enum might look something like this

 public enum ChargeGroupEnum
 {
    [Description("Administration")]
    Administration=1,
    [Description("Annual Leave")]
    AnnualLeave=2,
    [Description("Bereavement")]
    Bereavement=3,
    [Description("Customer Installation, Setup & Training")]
    CustomerInstallation=4,
    [Description("Customer Support")]
    CustomerSupport=5,
    [Description("Internal Training & Education")]
    InternalTraining=6,
    [Description("Sales & Marketing")]
    SalesMarketing=7,
    [Description("Sick")]
    Sick=8,
    [Description("Software Devel / Maint / Test")]
    Development=9,
    [Description("Software Upgrade / Patch")]
    Upgrade=10,
    [Description("Other")]
    Other=11,
    [Description("Other Absence")]
    OtherAbsence=12,
    [Description("Warranty")]
    Warranty=13,
    [Description("Public Holiday")]
    PublicHoliday=14,
    [Description(")ther Paid Leave")]
    OtherPaidLeave=15
}

And then on your View Model you could use the following to make the field start with no value and REQUIRE a value:

 [Required(ErrorMessage=" * required")]
 public ChargeGroupEnum? ChargeGroup {get;set;}

And then in your view you would use the Html Helper "ChargeGroupEnum" which you'll need to get from the post I linked to.

 @Html.EnumDropDownListFor(model => Model.ChargeGroup) 

If your model has an Int, you can easly go from Enum => Int and Int => Enum with casting.

Community
  • 1
  • 1
Nick Bork
  • 4,831
  • 1
  • 24
  • 25
  • 1
    I've updated the example to include how to call a Html Helper from Razor. The logic doesn't change, you use it just like you would use any of the other helper methods in MVC (Html, Url, etc). – Nick Bork Jan 11 '12 at 19:53
  • Interesting approach. Is the enum stored on the Viewmodel? – NoPyGod Jan 11 '12 at 20:25
  • What if the enum list needs to be loaded from a database table? – ca9163d9 Jan 11 '12 at 20:29
  • @NoPyGod the enum can be stored in the ViewModel or the Model or a common class. The location doesn't matter. You must create a property in your View Model that is of the enum type. – Nick Bork Jan 11 '12 at 20:34
  • @NickW if your list is database driven and you use an INT value as your property, like "ChargeGroupID", you could create a Html Helper that loaded the list of avaliable options from the databases, cached them to a static list and then created a select list based on the results. – Nick Bork Jan 11 '12 at 20:37
  • I would try to put the description text into a resource file, rather than encoding it in attributes on the enum. The names of the enum values can be used as the keys in the resource file, making it easy to look up the text with a given enum value. This makes it easy to localize the text, if desired. – Dr. Wily's Apprentice Jan 11 '12 at 20:47
  • @Dr.Wily'sApprentice , thats a good suggestion. The code example could be modified to search a common resource file for a description based on the full property name (MyProject.ViewModels.MyModel.ContactGroupEnum.Administration) and if nothing is found in the file, use the description and if no description use the enum value. – Nick Bork Jan 11 '12 at 21:06
  • @Splash-X - Hmm, we could also decorate the enum type with some kind of attribute that identifies the name of the resource file or embedded resource. That would allow us to use separate resource files for each enum. – Dr. Wily's Apprentice Jan 11 '12 at 21:21
  • @Dr.Wily'sApprentice I was able to find someone who used "Display" markup instead of "Description" to get the enum display from the resource, check out Max's code revision: http://stackoverflow.com/a/6810034/768804 In my opinion the code from Max is lacking in that you have to pass the type of the object. You shouldn't have to because you can get the type of the enum from the Expression. Either way, it's some code changes to the samples I provided but it's doable. – Nick Bork Jan 11 '12 at 21:55
0

I decided to keep the values for the select list on another class called OtherData which sits beside my main DBContext class in my models file.

NoPyGod
  • 4,905
  • 3
  • 44
  • 72
0

Wouldn't it be more ideal to create the SelectList in the view, vs. view model, just so the view models aren't AS tightly coupled to a view object (SelectList)?

I know a view model is for a view so tightly coupling them is more ok, but theoretically if the view is swapped out with something that doesn't use a SelectList, you could reuse more of the view model if it didn't use that SelectList.

wyntuition
  • 11
  • 3
0

I think that Caching that data after loading it from datasource and rendering the control based on that data through a helper method will be a better solution.

Jahan Zinedine
  • 14,616
  • 5
  • 46
  • 70
  • It's not loaded from a data source, it's just an array of values. My main concern is where do I keep the array of values? On the ViewModel, on the controller? The Viewbag.. etc – NoPyGod Jan 11 '12 at 20:26
  • That,s why I said load it from a datasource, cause every change in that list needs recompilation, redeploying, and it doesn't make sense, even you can save it in resource or xml file – Jahan Zinedine Jan 12 '12 at 06:30
-3
public static List<string> PaymentCurrency = new List<string> { "USD", "GBP", "EUR", "AUD", "BRL", "CAD", "CHF", "CLP", "CNY", "CZK", "DKK", "FJD", "HKD", "HNL", "HUF", "IDR", "ILS", "INR", "ISK", "JPY", "KRW", "LVL", "MXN", "MYR", "NOK", "NZD", "PHP", "PKR", "PLN", "RUB", "SEK", "SGD", "THB", "TRY", "TWD", "ZAR" };

List<SelectListItem> PaymentCurrencyOptionItems = new List<SelectListItem>() { new SelectListItem { Text = "", Value = "" } };
    PaymentCurrencyOptionItems.AddRange(Lolio.PaymentCurrency.Select(r => new SelectListItem { Text = r+" "+LangResources.Get("Currency_" + r), Value = r }));

IEnumerable<SelectListItem> LinkPaymentType = new SelectList(PaymentTypeOptionItems, "Value", "Text", lnk.Performance.PaymentType);

Html.DropDownListFor(m => m.PaymentType, LinkPaymentType))
Eric Yin
  • 8,737
  • 19
  • 77
  • 118