Как я могу заставить этот ASP.NET MVC SelectList работать?

126

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

Я пытаюсь создать это на лету, вроде того ... вот так ...

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>

Обратите внимание, как не выбран ни один элемент?

Как я могу это исправить??

Pure.Krome
источник
1
Шесть ответов ... один в избранное ... без голосов: / Я поставлю ему +1
womp

Ответы:

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()
    };

На второй взгляд я не уверен, что знаю, что вам нужно ...

mhenrixon
источник
2
Спасибо, это помогло мне разобраться в этом.
Cadoo,
6
Не решает проблему с выбранным элементом, но это отличный способ избежать волшебных строк для списков выбора! Ура
Алан Кристенсен
11
Чтобы исправить проблему с выбранным элементом, добавьте следующий код: SelectList sList = new SelectList(selectList, "Text", "Value", selected);где selectedтекущий выбранный покупатель
jao
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>, вы можете использовать синтаксис yield return, чтобы это выглядело по-настоящему чистым
Крис Мик,
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
приятный чувак :) мне нравится! я пытался сделать это .. но я не смог получить часть .Select (..) .. хорошо :) Я попробую это дома, позже :)
Pure.Krome
1
Привет, Кагдас. отлично работает, за исключением того, что выбранное поле не выбрано. любая идея? это ошибка в материале MVC?
Pure.Krome
2
Выбранный элемент работает, когда вы добавляете элемент SelectList в объект ViewData (как в ViewData ["myList"] = new SelectList ..), а затем визуализируете его с помощью <% = Html.DropDownList ("myList")%>. Я не мог заставить выбранный элемент работать, не сделав это таким образом. Weird.
ağdaş Tekin
@Cagdas - привет еще раз, чувак .. я до сих пор не понял этого :( Что такое с ViewData ??? У меня строго типизированный ViewData со своим собственным свойством .... ???
Pure.Krome
@ Pure.Krome - Я взял это свойство из вашего примера в вопросе. Сейчас редактирую образец кода. Пожалуйста, посмотрите мою правку через несколько секунд.
adaş 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)"указывать параметр optionLabel выше, если вам не нужен первый пустой элемент:

<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.

JustinStolle
источник
13

Проблема в том, что SelectList работает так, как задумано. Ошибка в дизайне. Вы можете установить свойство Selected в SelectedItem, но это будет полностью проигнорировано, если вы пройдете по списку с помощью GetEnumerator () (или если Mvc сделает это за вас). Вместо этого Mvc создаст новые SelectListItems.

Вы должны использовать SelectList ctor с SelectListItem [], Text-Name, Value-Name и SelectedValue. Помните, что в качестве SelectedValue нужно передавать ЗНАЧЕНИЕ 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" );

(не тестировал это, но у меня была такая же проблема)

то второй вариант получит атрибут selected = "selected". Это похоже на старые добрые DataSets ;-)

Исчезло кодирование
источник
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" },
}
murki
источник
новый SelectListItem {Selected = true, Text = "15", Value = "15"} для выбранного значения.
Cadoo,
упс, да, забыл включить свойство 'Selected', спасибо Cadoo =)
murki
10

Если это буквально все, что вы хотите сделать, то простое объявление массива в виде строки устраняет проблему с выбранным элементом:

myViewData.PageOptionsDropDown = 
   new SelectList(new string[] {"10", "15", "25", "50", "100", "1000"}, "15");
Матовый хлопок
источник
7

Заставить SelectList и SelectedValue работать вместе очень просто, даже если ваше свойство не является простым объектом, таким как значение типа Int, String или Double.

Пример:

Предположим, что наш объект Region выглядит примерно так:

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 объекта Region на что-то вроде:

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 для каждого элемента в коллекции элементов.

ararog
источник
5

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

Это, конечно, немного странно, но я попробовал, и это работает.

Итак, если у вашего класса есть поле с названием CountryId, скажем, и вы показываете список названий стран, сделайте раскрывающийся список с идентификатором 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

Цитирую Дэна Ватсона:

В MVC, если представление строго типизировано, выбранный параметр списка выбора будет переопределен, а свойство selected option, установленное в конструкторе, никогда не достигнет представления, и вместо этого будет выбран первый вариант в раскрывающемся списке (почему до сих пор остается загадкой) ,

ура!

cleftheris
источник
3

Все эти ответы выглядят великолепно, но похоже, что контроллер подготавливает данные для представления в хорошо известном структурированном формате, а не позволяет представлению просто повторять IEnumerable <>, доставленный через модель, и создавать стандартный список выбора, а затем позволить DefaultModelBinder доставить выбранный элемент обратно вам с помощью параметра действия. Да нет, а почему бы и нет? Разделение забот, да? Кажется странным, чтобы контроллер создавал что-то настолько специфичное для UI и View.


источник
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")%>
Cadoo
источник
Да, это тоже работает для меня. В моем случае список представляет собой объект модели сущности. Контроллер: ViewData ["Categories"] = новый SelectList (db.Categories.ToList (), "CategoryId", "CategoryName", "15"); View: Html.DropDownList ("CategoryId", (SelectList) ViewData ["Categories"], "--select--")
Джуниор Мэйхе
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 () решает проблемы.

femseks
источник
1

Если вы хотите передать какой-то случайный текст в свой DropDownList, например --Select -, вы можете легко сделать это с помощью этого кода:

@Html.DropDownListFor(x => x.CategoryId, new SelectList(Model.Categories, "Id", "Name"), "--Select--", new { @class = "form-control" })
Мюнхен
источник
0

Возможно, у вас есть некоторая двусмысленность в ваших ViewData:

Взгляните сюда

KP.
источник
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» является строкой в ​​вашей модели? Потому что в противном случае выбранное значение в списке не будет отображаться.

FruitDealer
источник
0

Если вы посмотрите исходный код для MVC 2 в методе расширения Html.DropDownList, он никогда не проверяет свойство SelectedValue класса SelectList. Он будет только когда-либо пытаться сопоставить с вашей моделью.

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

Проблема в представлении. Либо создайте свой собственный метод расширения DropDownList, который учитывает установленное вами значение select, либо выполните итерацию вручную. Что лучше всего подходит для вас.

Саймон Хэлси
источник
@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))
отметка
источник