Як я можу змусити цей ASP.NET MVC SelectList працювати?


126

Я створюю список вибору у своєму контролері для відображення у поданні.

Я намагаюся створити його на льоту, щось подібне ...

myViewData.PageOptionsDropDown = 
   new SelectList(new [] {"10", "15", "25", "50", "100", "1000"}, "15");

Він компілюється, але вихід поганий ...

<select id="PageOptionsDropDown" name="PageOptionsDropDown">
    <option>10</option>
    <option>15</option>
    <option>25</option>
    <option>50</option>
    <option>100</option>
    <option>1000</option>
</select>

Зауважте, як не вибрано жоден елемент?

Як я можу це виправити ??


1
Шість відповідей ... один вибраний ... жодних результатів: / Я дам йому +1
матка

Відповіді:


128

Ось як я це роблю

IList<Customer> customers = repository.GetAll<Customer>();
IEnumerable<SelectListItem> selectList = 
    from c in customers
    select new SelectListItem
    {
        Selected = (c.CustomerID == invoice.CustomerID),
        Text = c.Name,
        Value = c.CustomerID.ToString()
    };

На другий погляд я не впевнений, що я знаю, що ти після ...


2
Дякую, що це допомогло мені розібратися в цьому.
Cadoo

6
Виправлена ​​проблема не вибрана, але це прекрасний спосіб уникнути магічних рядків для вибраних списків! Ура
Алан Крістенсен

11
Для того, щоб зафіксувати обрану проблему елемента, додайте наступний код: SelectList sList = new SelectList(selectList, "Text", "Value", selected);де selectedзнаходиться поточний обраний клієнт
Джао

68

Я використовую метод розширення:

використання

var departmentItems = departments.ToSelectList(d => d.Code + 
                                               " - " + d.Description,
                                               d => d.Id.ToString(),
                                               " - ");

var functionItems = customerFunctions.ToSelectList(f => f.Description, 
                                                   f => f.Id.ToString(), 
                                                   " - ");

з

public static class MCVExtentions
{
    public static List<SelectListItem> ToSelectList<T>(
        this IEnumerable<T> enumerable, 
        Func<T, string> text, 
        Func<T, string> value, 
        string defaultOption)
    {
        var items = enumerable.Select(f => new SelectListItem()
                                     {
                                         Text = text(f), 
                                         Value = value(f) 
                                     }).ToList();
        items.Insert(0, new SelectListItem()
                    {
                        Text = defaultOption, 
                        Value = "-1" 
                    });
        return items;
    }
}

приємно. Я додав вибраний Func, параметр defaultValue і друге перевантаження без будь-яких стандартних параметрів, і це працює. До речі, якщо ви хочете зробити тип повернення IEnumerable <SelectListItem>, ви можете використовувати синтаксис повернення прибутковості, щоб це виглядало дійсно чисто
Chris Meek

48

Використання конструктора, який приймає items, dataValueField, dataTextField, selectedValueяк параметри:

ViewData["myList"] = 
                new SelectList(new[] { "10", "15", "25", "50", "100", "1000" }
                .Select(x => new {value = x, text = x}), 
                "value", "text", "15");

Тоді на ваш погляд:

<%=Html.DropDownList("myList") %>

3
приємний чувак :) мені подобається! я намагався це зробити .. але я не міг отримати. Виберіть (..) частину .. приємно :) Я спробую це вдома, пізніше :)
Pure.Krome

1
Хейя Кагдас. працює чудово, за винятком того, що вибране поле не вибране. будь-яка ідея? це помилка в речах MVC?
Pure.Krome

2
Вибраний елемент працює, коли ви додаєте елемент SelectList в об’єкт ViewData (як у ViewData ["myList"] = новий SelectList ..), а потім відтворюєте його з <% = Html.DropDownList ("myList")%>. Я не міг змусити вибраний елемент працювати, не роблячи це таким чином. Дивно.
Çağdaş Tekin

@Cagdas - привіт знову чувак .. Я досі не зрозумів цього :( Що це за ViewData ??? У мене є сильно набраний ViewData з його власним майном .... ???
Pure.Krome

@ Pure.Krome - я взяв цю власність із вашого прикладу в питанні. Тепер я редагую зразок коду. Будь ласка, перегляньте мою редакцію через кілька секунд.
Çağdaş Tekin

19

Спираючись на відповідь Томаса Стока, я створив такі перевантажені ToSelectListметоди:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.Mvc;

public static partial class Helpers
{
    public static IEnumerable<SelectListItem> ToSelectList<T>(this IEnumerable<T> enumerable, Func<T, object> value, bool selectAll = false)
    {
        return enumerable.ToSelectList(value, value, selectAll);
    }

    public static IEnumerable<SelectListItem> ToSelectList<T>(this IEnumerable<T> enumerable, Func<T, object> value, object selectedValue)
    {
        return enumerable.ToSelectList(value, value, new List<object>() { selectedValue });
    }

    public static IEnumerable<SelectListItem> ToSelectList<T>(this IEnumerable<T> enumerable, Func<T, object> value, IEnumerable<object> selectedValues)
    {
        return enumerable.ToSelectList(value, value, selectedValues);
    }

    public static IEnumerable<SelectListItem> ToSelectList<T>(this IEnumerable<T> enumerable, Func<T, object> value, Func<T, object> text, bool selectAll = false)
    {
        foreach (var f in enumerable.Where(x => x != null))
        {
            yield return new SelectListItem()
            {
                Value = value(f).ToString(),
                Text = text(f).ToString(),
                Selected = selectAll
            };
        }
    }

    public static IEnumerable<SelectListItem> ToSelectList<T>(this IEnumerable<T> enumerable, Func<T, object> value, Func<T, object> text, object selectedValue)
    {
        return enumerable.ToSelectList(value, text, new List<object>() { selectedValue });
    }

    public static IEnumerable<SelectListItem> ToSelectList<T>(this IEnumerable<T> enumerable, Func<T, object> value, Func<T, object> text, IEnumerable<object> selectedValues)
    {
        var sel = selectedValues != null
            ? selectedValues.Where(x => x != null).ToList().ConvertAll<string>(x => x.ToString())
            : new List<string>();

        foreach (var f in enumerable.Where(x => x != null))
        {
            yield return new SelectListItem()
            {
                Value = value(f).ToString(),
                Text = text(f).ToString(),
                Selected = sel.Contains(value(f).ToString())
            };
        }
    }
}

У своєму контролері ви можете зробити наступне:

var pageOptions = new[] { "10", "15", "25", "50", "100", "1000" };
ViewBag.PageOptions = pageOptions.ToSelectList(o => o, "15" /*selectedValue*/);

І, нарешті, у своєму представленні поставте:

@Html.DropDownList("PageOptionsDropDown", ViewBag.PageOptions as IEnumerable<SelectListItem>, "(Select one)")

Це призведе до отримання потрібного результату - звичайно, ви можете залишити параметр "(Select one)"Мітка вище, якщо ви не хочете першого порожнього елемента:

<select id="PageOptionsDropDown" name="PageOptionsDropDown">
<option value="">(Select one)</option>
<option value="10">10</option>
<option selected="selected" value="15">15</option>
<option value="25">25</option>
<option value="50">50</option>
<option value="100">100</option>
<option value="1000">1000</option>
</select>

Оновлення: переглянутий перелік коду можна знайти тут із коментарями XML.


13

Проблема полягає в тому, що SelectList працює як розроблено. Помилка в дизайні. Ви можете встановити вибрану властивість у SelectedItem, але це буде повністю проігноровано, якщо ви перейдете список за допомогою GetEnumerator () (або якщо Mvc робить це для вас). Mvc натомість створить нові SelectListItems.

Ви повинні використовувати ctor SelectList з SelectListItem [], Text-Name, Name-Name та SelectedValue. Будьте в курсі передати як SelectedValue значення VALUE SelectListItem, яке ви хочете обрати, а не сам SelectListItem! Приклад:

SelectList sl = new SelectList( new[]{
  new SelectListItem{ Text="one", Value="1"},
  new SelectListItem{ Text="two", Value="2"},
  new SelectListItem{ Text="three", Value="3"}
}, "Text", "Value", "2" );

(не перевіряв цього, але у мене була така ж проблема)

то 2-й варіант отримає атрибут selected = "selected". Це схоже на старі добрі набори даних ;-)


11

Це варіант:

myViewData.PageOptionsDropDown = new[] 
{
 new SelectListItem { Text = "10", Value = "10" },
 new SelectListItem { Text = "15", Value = "15", Selected = true }
 new SelectListItem { Text = "25", Value = "25" },
 new SelectListItem { Text = "50", Value = "50" },
 new SelectListItem { Text = "100", Value = "100" },
 new SelectListItem { Text = "1000", Value = "1000" },
}

новий SelectListItem {вибраний = вірно, текст = "15", значення = "15"} для вибраного значення.
Cadoo

oops, так, забув включити властивість "Вибране", спасибі Cadoo =)
murki

10

Якщо це буквально все, що ви хочете зробити, то просто оголосивши масив як рядок виправляє вибрану проблему елемента:

myViewData.PageOptionsDropDown = 
   new SelectList(new string[] {"10", "15", "25", "50", "100", "1000"}, "15");

7

Дуже просто змусити SelectList та SelectedValue працювати разом, навіть якщо ваша власність не є простим об'єктом, таким як значення Int, String або Double.

Приклад:

Якщо припустити, що наш об’єкт є приблизно таким:

public class Region {
     public Guid ID { get; set; }
     public Guid Name { get; set; }
}

А ваша модель перегляду - це щось на зразок:

public class ContactViewModel {
     public DateTime Date { get; set; }
     public Region Region { get; set; }
     public List<Region> Regions { get; set; }
}

Ви можете мати код нижче:

@Html.DropDownListFor(x => x.Region, new SelectList(Model.Regions, "ID", "Name")) 

Тільки якщо ви переосмислите метод ToString у регіоні об'єкта на щось на кшталт:

public class Region {
     public Guid ID { get; set; }
     public Guid Name { get; set; }

     public override string ToString()
     {
         return ID.ToString();
     }
}

Це 100% гарантія на роботу.

Але я дійсно вважаю, що найкращим способом змусити SelectList на 100% працювати у всіх циркуляціях - це за допомогою методу Equals для тестування значення властивостей DropDownList або ListBox щодо кожного елемента в колекції елементів.


5

Здається, якщо у вас сильно набраний вид, вам потрібно змінити ідентифікатор випадаючого меню, щоб він НЕ був іменем властивості у спадковому класі. Тоді вам потрібно ввести певну логіку в метод редагування (POST), щоб вийняти вибране значення з FORMCollection і поставити його до свого примірника, перш ніж вносити зміни.

Це, звичайно, трохи дивно, але я спробував це, і він працює.

Отже, якщо в класі є поле під назвою CountryId say, і ви відображаєте список імен країн, зробіть спадне меню ідентифікатором CountryName, а не CountryId, тоді в дописі ви можете зробити щось із Collection ["CountryName"] .


1
Так, у мене була ця сама проблема. Просто зміна назви працювала. Дякую!
davekaro

4

У мене була точно така ж проблема. Рішення просте. Просто змініть параметр "name", переданий помічнику DropDownList, на те, що не відповідає жодному з властивостей, що існують у ViewModel. докладніше читайте тут: http://www.dotnetguy.co.uk/post/2009/06/25/net-mvc-selectlists-selected-value-does-not-get-set-in-the-view

Я цитую Dan Watson:

У MVC, якщо представлення сильно набрано, вибраний параметр listlist буде відмінено, а вибране властивість параметра, встановлене в конструкторі, ніколи не дійде до перегляду, а замість нього буде вибрано перший варіант у спадному меню (чому все ще є трохи таємницею) .

ура!


3

Усі ці відповіді виглядають чудово, але здається, що контролер готує дані для представлення у добре відомій структурованому форматі порівняно з тим, щоб перегляд просто ітеравав IEnumerable <>, що постачається через модель, і створює стандартний список вибору, а потім нехай DefaultModelBinder доставити вибраний елемент вам за допомогою параметра дії. Так, ні, чому б і ні? Поділ проблем, так? Дивно здається, що контролер може скласти щось таке, що відповідає інтерфейсу та перегляду.


3

Простий:

string[] someName = new string[] {"10", "15", "25", "50", "100", "1000"};
myViewData.PageOptionsDropDown = new SelectList(someName, "15");

2

Я просто запустив це так і не мав проблем,

public class myViewDataObj
    {
        public SelectList PageOptionsDropDown { get; set; }
    }

public ActionResult About()
        {
            myViewDataObj myViewData = new myViewDataObj();
            myViewData.PageOptionsDropDown =
                  new SelectList(new[] { "10", "15", "25", "50", "100", "1000" }, "15");

            ViewData["myList"] = myViewData.PageOptionsDropDown;
            return View();
        }

і

<%=Html.DropDownList("myList") %>

це також спрацювало, якщо ви це зробите,

public ActionResult About()
        {
            myViewDataObj myViewData = new myViewDataObj();
            myViewData.PageOptionsDropDown =
                  new SelectList(new[] { "10", "15", "25", "50", "100", "1000" });

            ViewData["myListValues"] = myViewData.PageOptionsDropDown;
            ViewData["myList"] = "15";
            return View();
        }

і

<%=Html.DropDownList("myList",(IEnumerable<SelectListItem>)ViewData["myListValues"]) %>

1

Використовуючи ваш приклад, це працювало для мене:

контролер:

ViewData["PageOptionsDropDown"] = new SelectList(new[] { "10", "15", "25", "50", "100", "1000" }, "15");

вид:

<%= Html.DropDownList("PageOptionsDropDown")%>

Так, це теж працює для мене. У моєму випадку список є об’єктом Entity Model. Контролер: ViewData ["Категорії"] = новий SelectList (db.Categories.ToList (), "CategoryId", "CategoryName", "15"); Перегляд: Html.DropDownList ("CategoryId", (SelectList) ViewData ["Категорії"], "
вибір

1
MonthRepository monthRepository = new MonthRepository();
IQueryable<MonthEntity> entities = monthRepository.GetAllMonth();
List<MonthEntity> monthEntities = new List<MonthEntity>();

foreach(var r in entities)
{
    monthEntities.Add(r);
}

ViewData["Month"] = new SelectList(monthEntities, "MonthID", "Month", "Mars");

1

Я роблю це так:

List<SelectListItem> list = new List<SelectListItem>{
new SelectListItem {Selected = true, Text = "Select", Value = "0"},
new SelectListItem {Selected = true, Text = "1", Value = "1"},
new SelectListItem {Selected = true, Text = "2", Value = "2"}
};
return list.ToArray();

ToArray () піклується про проблеми.


1

Якщо ви хочете передати якийсь випадковий текст у свій DropDownList, наприклад --Select--, ви можете легко зробити це за допомогою цього коду:

@Html.DropDownListFor(x => x.CategoryId, new SelectList(Model.Categories, "Id", "Name"), "--Select--", new { @class = "form-control" })

0

Можливо, у вашому ViewData є певна неоднозначність:

Погляньте тут


0

значення, вибране в моделі, має перевагу замість елемента за замовчуванням. (Я згоден, що я не прочитав усі повідомлення)


0

Я не можу пригадати, як був налаштований mvc 1, але, схоже, він хотів, щоб список виділених був таким самим, як і поле, до якого теж належав ...

Я знайшов, як хтось сказав вище, те, що мої списки вибору не працювали в mvc2, коли ViewData, яким вони були надіслані, був названий таким же, як і поле.

Наприклад:

<%= Html.DropDownListFor((model => model.ForID), (SelectList)ViewData["ForName"]) %>

працює, коли

<%= Html.DropDownListFor((model => model.ForID), (SelectList)ViewData["ForID"]) %>

не працює, оскільки ім'я ViewData "ForID" названо так само, як і поле, для якого він працює


0

Можливе пояснення полягає в тому, що значення списку вибору, до якого ви прив'язуєтесь, не є рядком.

Отже, у цьому прикладі параметр 'PageOptionsDropDown' є рядком у вашій моделі? Тому що якщо це не так, вибране значення у списку не відображатиметься.


0

Якщо ви шукаєте вихідний код для MVC 2 за методом розширення Html.DropDownList, він ніколи не перевіряє властивість SelectList Class SelectedValue. Він лише намагатиметься відповідати вашій моделі.

Все вищезазначене - це всі варіанти теми, тобто, як ви надсилаєте купу даних до представленого списку для випадаючого списку, і всі вони настільки ж хороші, як один одному (більш-менш).

Проблема полягає в погляді. Або створіть свій власний метод розширення DropDownList, який би відповідав вибраній вами значенню, або повторіть вручну. Що завжди найкраще працює для вас.


@Franz Antesberger говорить майже те саме.
Саймон Халсі

0

Якщо у вас є колекція у вашій моделі, а ваш Вид сильно набраний, деякі варіанти цього спрацюють:

@Html.DropDownListFor(x => x.RegionID, 
    new SelectList(Model.Regions,"RegionID", "RegionName", Model.RegionID))

або

@Html.DropDownList("RegionID", 
    new SelectList(Model.Regions, "RegionID", "RegionName", Model.RegionID))
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.