ASP.NET MVC Html.DropDownList SelectedValue


103

나는 이것이 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의 항목은 목록 내에 있지만 목록의 첫 번째 항목은 항상 기본적으로 선택됩니다.

어떻게해야합니까?

업데이트 John Feminella의 답변 덕분에 문제가 무엇인지 알아 냈습니다. "UserId"는 내 뷰가 강력하게 입력되는 모델의 속성입니다. Html.DropDownList ( "UserId"가 "UserId"가 아닌 다른 이름으로 변경되면 선택한 값이 올바르게 렌더링됩니다.

이로 인해 값이 모델에 바인딩되지 않습니다.


값이 목록에 있는지 확실합니까?
John Sheehan

ASP.NET MVC의 릴리스 1
Mathias F

selectedUserId!는 무엇입니까?
fulvio 2010

입력의 이름이 속성과 동일하지 않은 경우 업데이트시 값을 바인딩하는 방법은 무엇입니까?
ryudice

답변:


68

이 문제를 해결 한 방법입니다.

나는 다음을 가졌다 :

제어 장치:

ViewData["DealerTypes"] = Helper.SetSelectedValue(listOfValues, selectedValue) ;

전망

<%=Html.DropDownList("DealerTypes", ViewData["DealerTypes"] as SelectList)%>

다음에 의해 변경 :

전망

<%=Html.DropDownList("DealerTypesDD", ViewData["DealerTypes"] as SelectList)%>

DropDown은 ViewData 이름이 같은 이름을 가져서는 안되는 것 같습니다 : S 이상하지만 작동했습니다.


19
+1 "DropDown은 ViewData 이름과 같은 이름을 가져서는 안됩니다"Big Thanks
Daniel Dyson

감사합니다!!! 이 :) 작동하지 않았다 왜 그냥 궁금 여러 시간 후에 내 문제를 해결

1
이것은 선택된 값에 대해 작동하지만, DropDownList가 이제 모델에 존재하지 않는 "DealerTypesDD"에 바인딩되어 있기 때문에 db에서 "DealerTypes"를 업데이트하려고하면 문제가 발생합니다. 해결 방법은 숨겨진 필드와 htmlAttributes를 DropDownList에 추가하는 것입니다. <input type = "hidden"name = "DealerTypes"id = "DealerTypes"value = ""/> <% = Html.DropDownList ( "DealerTypesDD", ViewData [ "DealerTypes"] as SelectList, new {@onchange = "DealerTypes.value = this.value"}) %>
Zim

3
뷰 데이터 이름에 'DS'를 추가하는 것이 더 낫습니다. 따라서 모델 바인딩이
손상

1
도대체! 이것은 MVC5에서 수정되지 않습니까 ??? @Paul Hatcher가 언급 한 또 다른 트릭으로 선택한 ID를 ViewData [ "DealerTypes"]에 복사합니다.
jsgoupil

51

이 시도:

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>

이것은 원인을 추적하는 데 도움이되었습니다. 추가 사항을 반영하기 위해 질문을 업데이트했습니다.
blu

모델 1 위인가요? 컨트롤러에서 두 번째? 세 번째는 명확하지만 첫 번째는 2 개 .. ???
rr

좋은 대답이지만 ViewModel을 사용하는 것이 더 낫지 않습니까?
Jess

@Jess : 5 년 전인 2009 년 3 월에이 답변을 썼습니다. 시대가 바뀌 었습니다! 자유롭게 업데이트하십시오. :)
John Feminella

5

DropDown의 이름을 "UserId"로 지정하고 모델 바인딩이 올바르게 작동하도록 할 수 있습니다.

이 작업을 수행하기위한 유일한 요구 사항은 SelectList를 포함하는 ViewData 키가 바인딩하려는 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"])%>

그러면 모델의 UserId 속성과 이름이 같은 UserId라는 선택 요소가 생성되므로 모델 바인더는 Html.DropDownList 도우미가 생성 한 html의 선택 요소에서 선택한 값으로이를 설정합니다.

속성 이름과 동일한 키를 사용하여 ViewData에 선택 목록을 넣을 때 특정 Html.DropDownList 생성자가 SelectList에 지정된 값을 선택하지 않는 이유를 잘 모르겠습니다. 다른 시나리오에서 DropDownList 도우미가 사용되는 방식과 관련이 있다고 생각합니다. 관례는 모델의 속성과 동일한 이름을 가진 ViewData에 SelectList가 있다는 것입니다. 이것은 올바르게 작동합니다.

// in my controller
ViewData["UserId"] = new SelectList(
    users, 
    "UserId", 
    "DisplayName", 
    selectedUserId.Value); // this has a value

// in my view
<%=Html.DropDownList("UserId")%>

많은 친구에게 감사합니다. 무엇보다도 이것이 저에게 효과가 있었지만 이유는 모르겠지만 그랬습니다
Lamin Sanneh

드디어! 몇 시간의 노력 끝에 마침내 "유일한 요구 사항"을 찾았습니다. 그게됐다.
SteveCav

2

이것이 팀이 수정해야하는 버그라고 생각하지 않는다면 MSDN은 문서를 개선해야합니다. 혼란스러운 것은 이것에 대한 잘못된 문서에서 비롯됩니다. MSDN 에서는 매개 변수 이름을 다음 과 같이 설명합니다 .

Type: System.String
The name of the form field to return.

이것은 생성하는 최종 html이 해당 매개 변수를 선택 입력의 이름으로 사용함을 의미합니다. 하지만 실제로는 그 이상을 의미합니다.

디자이너는 사용자가보기 모델을 사용하여 드롭 다운 목록을 표시하고 동일한 보기 모델로 다시 게시 할 것이라고 가정합니다 . 그러나 많은 경우에 우리는 그 가정을 실제로 따르지 않습니다.

위의 예를 사용하십시오.

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> Persons가 이미 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);
}

따라서 코드는 실제로 더 나아갔습니다. 모델에서 이름을 조회 할뿐만 아니라 뷰 데이터에서도 이름을 찾으면 selectList를 다시 빌드하고 원래 Selected를 무시합니다.

문제는 많은 경우에 우리는 실제로 그렇게 사용하지 않는다는 것입니다. 우리는 하나 / 여러 항목이 선택된 selectList를 true로 설정하기를 원합니다.

물론 솔루션은 간단합니다. 모델이나 뷰 데이터에없는 이름을 사용하십시오. 일치하는 항목을 찾을 수없는 경우 원래 selectList를 사용하고 원래 Selected가 적용됩니다.

하지만 여전히 mvc가 조건을 하나 더 추가하여 개선해야한다고 생각합니다.

if ((defaultValue != null) && (!selectList.Any(i=>i.Selected)))
{
    selectList = GetSelectListWithDefaultValue(selectList, defaultValue, allowMultiple);
}

원래 selectList에 이미 하나의 Selected가있는 경우이를 무시하는 이유는 무엇입니까?

내 생각뿐입니다.


이것은 내가 지금까지 읽은 가장 좋은 설명입니다. 많은 두통을 덜어주었습니다. 내가해야 할 일은 viewmodel 속성의 값을 설정하는 것이었고 작동했습니다. 감사.
모세 Machua

2

이전 MVC 3 게시물의 코드는 작동하지 않지만 좋은 시작입니다. 내가 고칠 게. 이 코드를 테스트했으며 MVC 3 Razor C #에서 작동합니다.이 코드는 ViewModel 패턴을 사용하여 List<SelectListItem>.

모델 클래스

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>

출력 형식에 따라 다릅니다. 이게 도움이 되길 바란다. 코드가 작동합니다.


1
이것은 selected옵션을 설정하지 않습니다 .
Jess

SelectListItem을 사용하여 선택한 항목을 설정하려면 Selected 속성을 true로 설정합니다.
wayne.blackmon

1

선택한 항목에 대한 모델이 아닌 ViewData 만 확인하므로 SelectExtensions 클래스의 버그로 보입니다. 따라서 트릭은 모델에서 선택한 항목을 속성 이름으로 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()) %>

이것은보기 모델의 ArticleType을 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);
     }
     ...
}

답장을 보내 주셔서 감사합니다.
blu

0

문제는 드롭 박스가 적어도 ASP.NET MVC2 디자인이 기대하는 방식으로 목록 박스와 동일하게 작동하지 않는다는 것입니다. 드롭 박스는 여러 값을 선택할 수 있으므로 드롭 박스는 0 개 또는 1 개의 값만 허용합니다. 따라서 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가 드롭 박스를 렌더링하고 특정 값 (예 : 기본값 등)을 선택하도록하려면 다음과 같이 렌더링에 값을 지정해야합니다.

// in my view             
<%=Html.DropDownList("UserId", selectListItems /* (SelectList)ViewData["UserId"]*/, new { @Value = selectedUser.Id } /* Your selected value as an additional HTML attribute */)%>

0

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 호출에서 목록을 수동으로 "사용"할 필요가 없습니다. 이렇게하면 선택한 값도 올바르게 설정됩니다.

부인 성명:

  1. 웹 양식보기 엔진에서 이것을 시도하지 않았지만 역시 작동합니다.
  2. 나는 이것을 v1과 v2에서 테스트하지 않았지만 작동 할 수 있습니다.

0

나는 원하는 결과를 얻었지만 약간 다른 접근 방식을 사용했습니다. 드롭 다운 목록에서 모델을 사용한 다음 참조했습니다. 이것이 당신이 찾고 있던 것인지 확실하지 않습니다.

@Html.DropDownList("Example", new SelectList(Model.FeeStructures, "Id", "NameOfFeeStructure", Model.Matters.FeeStructures))

위의 Model.Matters.FeeStructures는 선택해야 할 항목의 가치가 될 수있는 내 ID입니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.