Подтвердить что ты не робот

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" , выбранное значение отображается правильно.

Это приводит к тому, что значение не связано с моделью.

4b9b3361

Ответ 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, но он может работать.