ASP.NET MVC Html.DropDownList SelectedValue
Я пробовал это RC1, а затем обновился до RC2, который не разрешил проблему.
// in my controller
ViewData["UserId"] = new SelectList(
users,
"UserId",
"DisplayName",
selectedUserId.Value); // this has a value
результат: свойство SelectedValue установлено на объекте
// in my view
<%=Html.DropDownList("UserId", (SelectList)ViewData["UserId"])%>
Результат: все ожидаемые параметры отображаются клиенту, но выбранный атрибут не установлен. Элемент в SelectedValue существует в списке, но первый элемент в списке всегда выбран по умолчанию.
Как мне это сделать?
Обновление
Благодаря ответу Джона Фэминеллы я выяснил, в чем проблема. "UserId" - это свойство в Model my View, которое строго типизировано. Когда Html.DropDownList( "UserId" изменен на любое другое имя, но "UserId" , выбранное значение отображается правильно.
Это приводит к тому, что значение не связано с моделью.
Ответы
Ответ 1
Вот как я исправил эту проблему:
У меня было следующее:
Контроллер:
ViewData["DealerTypes"] = Helper.SetSelectedValue(listOfValues, selectedValue) ;
Вид
<%=Html.DropDownList("DealerTypes", ViewData["DealerTypes"] as SelectList)%>
Изменено следующим образом:
Просмотр
<%=Html.DropDownList("DealerTypesDD", ViewData["DealerTypes"] as SelectList)%>
Похоже, что DropDown не должен иметь одно имя с именем ViewData: S weird, но он сработал.
Ответ 2
Попробуйте следующее:
public class Person {
public int Id { get; set; }
public string Name { get; set; }
}
И затем:
var list = new[] {
new Person { Id = 1, Name = "Name1" },
new Person { Id = 2, Name = "Name2" },
new Person { Id = 3, Name = "Name3" }
};
var selectList = new SelectList(list, "Id", "Name", 2);
ViewData["People"] = selectList;
Html.DropDownList("PeopleClass", (SelectList)ViewData["People"])
С MVC RC2 я получаю:
<select id="PeopleClass" name="PeopleClass">
<option value="1">Name1</option>
<option selected="selected" value="2">Name2</option>
<option value="3">Name3</option>
</select>
Ответ 3
Вы все еще можете назвать DropDown как "UserId" и по-прежнему имеете правильную привязку модели для вас.
Единственным требованием для этого является то, что ключ ViewData, содержащий SelectList, не имеет того же имени, что и свойство Model, которое вы хотите связать. В вашем конкретном случае это будет:
// in my controller
ViewData["Users"] = new SelectList(
users,
"UserId",
"DisplayName",
selectedUserId.Value); // this has a value
// in my view
<%=Html.DropDownList("UserId", (SelectList)ViewData["Users"])%>
Это создаст элемент select с именем UserId, который имеет то же имя, что и свойство UserId в вашей модели, и поэтому связующее устройство модели установит его со значением, выбранным в элементе select html, сгенерированном помощником Html.DropDownList.
Я не уверен, почему этот конкретный конструктор Html.DropDownList не будет выбирать значение, указанное в SelectList, когда вы помещаете список выбора в ViewData с ключом, равным имени свойства. Я подозреваю, что это имеет какое-то отношение к тому, как помощник DropDownList используется в других сценариях, где соглашение заключается в том, что у вас есть SelectList в ViewData с тем же именем, что и свойство в вашей модели. Это будет работать правильно:
// in my controller
ViewData["UserId"] = new SelectList(
users,
"UserId",
"DisplayName",
selectedUserId.Value); // this has a value
// in my view
<%=Html.DropDownList("UserId")%>
Ответ 4
Код в предыдущем сообщении MVC 3 не работает, но это хороший старт. Я починю это. Я тестировал этот код и работает в MVC 3 Razor С# Этот код использует шаблон ViewModel для заполнения свойства, которое возвращает List<SelectListItem>
.
Класс Model
public class Product
{
public string Name { get; set; }
public decimal Price { get; set; }
}
Класс ViewModel
using System.Web.Mvc;
public class ProductListviewModel
{
public List<SelectListItem> Products { get; set; }
}
Метод контроллера
public ViewResult List()
{
var productList = new List<SelectListItem>();
foreach (Product p in Products)
{
productList.Add(new SelectListItem
{
Value = p.ProductId.ToString(),
Text = "Product: " + p.Name + " " + p.Price.ToString(),
// To set the selected item use the following code
// Note: you should not set every item to selected
Selected = true
});
}
ProductListViewModel productListVM = new ProductListViewModeld();
productListVM.Products = productList;
return View(productListVM);
}
Вид
@model MvcApp.ViewModels.ProductListViewModel
@using (Html.BeginForm())
{
@Html.DropDownList("Products", Model.Products)
}
Выход HTML будет выглядеть как
<select id="Products" name="Products">
<option value="3">Product: Widget 10.00</option>
<option value="4">Product: Gadget 5.95</option>
</select>
в зависимости от того, как вы форматируете выход. Надеюсь, это поможет. Код работает.
Ответ 5
Если мы не думаем, что это ошибка, которую команда должна исправить, в аренду MSDN должен улучшить документ. Заблуждение действительно происходит из плохого документа об этом. В MSDN он объясняет параметры name как,
Type: System.String
The name of the form field to return.
Это означает, что окончательный html, который он создает, будет использовать этот параметр в качестве имени входа select. Но это на самом деле означает больше.
Я предполагаю, что разработчик предполагает, что пользователь будет использовать модель представления для отображения выпадающего списка, а также будет использовать пост обратно в модель той же. Но во многих случаях мы действительно не следуем этому предположению.
Используйте приведенный выше пример,
public class Person {
public int Id { get; set; }
public string Name { get; set; }
}
Если мы будем следовать предположению, мы должны определить модель представления для этого связанного списка с выпадающим списком
public class PersonsSelectViewModel{
public string SelectedPersonId,
public List<SelectListItem> Persons;
}
Потому что, когда вы отправляете сообщение назад, только выбранное значение будет отсылаться обратно, поэтому предполагается, что он должен вернуться к свойству модели SelectedPersonId, что означает, что имя первого параметра Html.DropDownList должно быть "SelectedPersonId". Таким образом, дизайнер считает, что при отображении представления модели в представлении свойство модели SelectedPersonId должно содержать значение по умолчанию этого раскрывающегося списка. Даже если ваш List <SelectListItem> Person уже установил флажок Selected, чтобы указать, какой из них выбран/по умолчанию, tml.DropDownList фактически проигнорирует это и перестроит его собственный IEnumerable <SelectListItem> и задает элемент по умолчанию/выбранный на основе имени.
Вот код из asp.net mvc
private static MvcHtmlString SelectInternal(this HtmlHelper htmlHelper, ModelMetadata metadata,
string optionLabel, string name, IEnumerable<SelectListItem> selectList, bool allowMultiple,
IDictionary<string, object> htmlAttributes)
{
...
bool usedViewData = false;
// If we got a null selectList, try to use ViewData to get the list of items.
if (selectList == null)
{
selectList = htmlHelper.GetSelectData(name);
usedViewData = true;
}
object defaultValue = (allowMultiple) ? htmlHelper.GetModelStateValue(fullName, typeof(string[])) : htmlHelper.GetModelStateValue(fullName, typeof(string));
// If we haven't already used ViewData to get the entire list of items then we need to
// use the ViewData-supplied value before using the parameter-supplied value.
if (defaultValue == null && !String.IsNullOrEmpty(name))
{
if (!usedViewData)
{
defaultValue = htmlHelper.ViewData.Eval(name);
}
else if (metadata != null)
{
defaultValue = metadata.Model;
}
}
if (defaultValue != null)
{
selectList = GetSelectListWithDefaultValue(selectList, defaultValue, allowMultiple);
}
...
return tagBuilder.ToMvcHtmlString(TagRenderMode.Normal);
}
Итак, код действительно пошел дальше, он не только попытается найти имя в модели, но и в viewdata, как только он найдет его, он перестроит selectList и проигнорирует исходный выбранный.
Проблема в том, что во многих случаях мы не используем ее так. мы просто хотим вставить selectList с одним или несколькими элементами. Выбранный набор true.
Конечно, решение простое, используйте имя, которое не в модели, так и в viewdata. Когда он не сможет найти совпадение, он будет использовать оригинальный selectList, и исходный выбранный будет влиять.
Но я все еще думаю, что mvc должен улучшить его, добавив еще одно условие
if ((defaultValue != null) && (!selectList.Any(i=>i.Selected)))
{
selectList = GetSelectListWithDefaultValue(selectList, defaultValue, allowMultiple);
}
Потому что, если в исходном selectList уже был выбран один, почему вы проигнорируете это?
Только мои мысли.
Ответ 6
Это кажется ошибкой в классе SelectExtensions, поскольку он будет проверять только ViewData, а не модель для выбранного элемента. Итак, фокус в том, чтобы скопировать выбранный элемент из модели в коллекцию ViewData под именем свойства.
Это взято из ответа, который я дал на форумах MVC, у меня также есть более полный ответ в сообщении в котором используется Атрибут Kazi DropDownList...
Учитывая модель
public class ArticleType
{
public Guid Id { get; set; }
public string Description { get; set; }
}
public class Article
{
public Guid Id { get; set; }
public string Name { get; set; }
public ArticleType { get; set; }
}
и базовой модели представления
public class ArticleModel
{
public Guid Id { get; set; }
public string Name { get; set; }
[UIHint("DropDownList")]
public Guid ArticleType { get; set; }
}
Затем мы пишем шаблон редактора DropDownList следующим образом.
<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl" %>
<script runat="server">
IEnumerable<SelectListItem> GetSelectList()
{
var metaData = ViewData.ModelMetadata;
if (metaData == null)
{
return null;
}
var selected = Model is SelectListItem ? ((SelectListItem) Model).Value : Model.ToString();
ViewData[metaData.PropertyName] = selected;
var key = metaData.PropertyName + "List";
return (IEnumerable<SelectListItem>)ViewData[key];
}
</script>
<%= Html.DropDownList(null, GetSelectList()) %>
Это также будет работать, если вы измените ItemType в модели представления на SelectListItem, хотя вам необходимо реализовать конвертер типов в соответствии с блоком Kazi и зарегистрировать его, чтобы заставить связующее рассматривать это как простой тип.
В вашем контроллере мы тогда имеем...
public ArticleController
{
...
public ActionResult Edit(int id)
{
var entity = repository.FindOne<Article>(id);
var model = builder.Convert<ArticleModel>(entity);
var types = repository.FindAll<ArticleTypes>();
ViewData["ArticleTypeList"] = builder.Convert<SelectListItem>(types);
return VIew(model);
}
...
}
Ответ 7
Проблемы в том, что dropboxes не работают так же, как и списки, по крайней мере так, как ожидает проект ASP.NET MVC2: Dropbox допускает только ноль или одно значение, поскольку список может иметь множественный выбор значения. Таким образом, будучи строгим с HTML, это значение не должно быть в списке опций как "выбранный" флаг, а в самом входе.
См. следующий пример:
<select id="combo" name="combo" value="id2">
<option value="id1">This is option 1</option>
<option value="id2" selected="selected">This is option 2</option>
<option value="id3">This is option 3</option>
</select>
<select id="listbox" name="listbox" multiple>
<option value="id1">This is option 1</option>
<option value="id2" selected="selected">This is option 2</option>
<option value="id3">This is option 3</option>
</select>
Комбинация имеет выбранную опцию, но также имеет свой атрибут значений. Итак, если вы хотите, чтобы ASP.NET MVC2 отображал dropbox, а также имел определенное значение (то есть значения по умолчанию и т.д.), Вы должны дать ему значение в рендеринге, например:
// in my view
<%=Html.DropDownList("UserId", selectListItems /* (SelectList)ViewData["UserId"]*/, new { @Value = selectedUser.Id } /* Your selected value as an additional HTML attribute */)%>
Ответ 8
В ASP.NET MVC 3 вы можете просто добавить свой список в ViewData...
var options = new List<SelectListItem>();
options.Add(new SelectListItem { Value = "1", Text = "1" });
options.Add(new SelectListItem { Value = "2", Text = "2" });
options.Add(new SelectListItem { Value = "3", Text = "3", Selected = true });
ViewData["options"] = options;
... и затем ссылайтесь на него по имени в вашем бритве...
@Html.DropDownList("options")
Вам не нужно вручную "использовать" список в вызове DropDownList. Для этого правильно установите для меня также выбранное значение.
Отказ от ответственности:
- Не пробовал это с помощью механизма просмотра веб-форм, но он тоже должен работать.
- Я не тестировал это в v1 и v2, но он может работать.