ASP.NET MVC Html.DropDownList SelectedValue


103

Tôi đã thử đây là RC1 và sau đó nâng cấp lên RC2 mà không giải quyết được sự cố.

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

kết quả: thuộc tính SelectedValue được đặt trên đối tượng

// in my view
<%=Html.DropDownList("UserId", (SelectList)ViewData["UserId"])%>

kết quả: tất cả các tùy chọn mong đợi được hiển thị cho máy khách, nhưng thuộc tính đã chọn không được đặt. Mục trong SelectedValue tồn tại trong danh sách, nhưng mục đầu tiên trong danh sách luôn được đặt mặc định là đã chọn.

Tôi nên làm điều này như thế nào?

Cập nhật Cảm ơn câu trả lời của John Feminella, tôi đã tìm ra vấn đề là gì. "UserId" là một thuộc tính trong Mô hình Chế độ xem của tôi được nhập mạnh. Khi Html.DropDownList ("UserId" được thay đổi thành bất kỳ tên nào khác ngoài "UserId", giá trị đã chọn được hiển thị chính xác.

Điều này dẫn đến giá trị không bị ràng buộc với mô hình.


Bạn có chắc chắn rằng giá trị có trong danh sách không?
John Sheehan

Sự cố vẫn tồn tại trong Bản phát hành 1 của ASP.NET MVC
Mathias F

SelectUserId là gì !?
fulvio

Bạn giả sử ràng buộc giá trị khi cập nhật như thế nào nếu tên của đầu vào không giống với thuộc tính của bạn?
ryudice

Câu trả lời:


68

Đây là cách tôi khắc phục sự cố này:

Tôi đã có những điều sau đây:

Bộ điều khiển:

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

Lượt xem

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

Được thay đổi như sau:

Lượt xem

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

Có vẻ như DropDown không được trùng tên có tên ViewData: S lạ nhưng nó đã hoạt động.


19
1 cho "thả xuống không phải có cùng tên có tên ViewData" Big Cảm ơn
Daniel Dyson

Cảm ơn bạn!!! Bạn vừa giải quyết được vấn đề của tôi sau nhiều giờ tự hỏi tại sao điều này không thành công :)
Jen

1
Điều này hoạt động cho giá trị đã chọn, nhưng một vấn đề phát sinh khi bạn cố gắng cập nhật "DealerTypes" trong db vì nó là DropDownList hiện bị ràng buộc với "DealerTypesDD" không tồn tại trong mô hình. Cách giải quyết là thêm trường ẩn và htmlAttributes vào DropDownList: <input type = "hidden" name = "DealerTypes" id = "DealerTypes" value = "" /> <% = Html.DropDownList ("DealerTypesDD", ViewData [ "DealerTypes"] dưới dạng SelectList, mới {@onchange = "DealerTypes.value = this.value"})%>
Zim

3
Bạn nên thêm 'DS' với tên ViewData, do đó không làm hỏng các ràng buộc mô hình ...
noocyte

1
Cái quái gì thế! Điều này không được sửa trong MVC5 ??? Như một thủ thuật khác được @Paul Hatcher đề cập, hãy sao chép id đã chọn vào ViewData ["DealerTypes"].
jsgoupil

51

Thử cái này:

public class Person {
    public int Id { get; set; }
    public string Name { get; set; }
}

Và sau đó:

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"])

Với MVC RC2, tôi nhận được:

<select id="PeopleClass" name="PeopleClass">
    <option value="1">Name1</option>
    <option selected="selected" value="2">Name2</option>
    <option value="3">Name3</option>
</select>

Điều này rất hữu ích trong việc theo dõi nguyên nhân. Tôi đã cập nhật câu hỏi của mình để phản ánh những bổ sung.
blu

là đầu tiên trong mô hình? thứ hai trong bộ điều khiển? và thứ ba xem nó rõ ràng, nhưng 2 cái đầu tiên .. ???
rr

Câu trả lời hay, nhưng sử dụng ViewModel có tốt hơn không?
Jess

@Jess: Tôi đã viết câu trả lời này vào tháng 3 năm 2009, hơn 5 năm trước. Thời gian đã thay đổi! Vui lòng cập nhật. :)
John Feminella

5

Bạn vẫn có thể đặt tên DropDown là "UserId" và vẫn có liên kết mô hình hoạt động chính xác cho bạn.

Yêu cầu duy nhất để điều này hoạt động là khóa ViewData chứa SelectList không có cùng tên với thuộc tính Model mà bạn muốn liên kết. Trong trường hợp cụ thể của bạn, điều này sẽ là:

// 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"])%>

Điều này sẽ tạo ra một phần tử được chọn có tên là UserId, có cùng tên với thuộc tính UserId trong mô hình của bạn và do đó trình kết nối mô hình sẽ đặt nó với giá trị được chọn trong phần tử chọn của html được tạo bởi trình trợ giúp Html.DropDownList.

Tôi không chắc tại sao hàm tạo Html.DropDownList cụ thể đó sẽ không chọn giá trị được chỉ định trong SelectList khi bạn đặt danh sách chọn trong ViewData với khóa bằng tên thuộc tính. Tôi nghi ngờ rằng nó có liên quan đến cách trình trợ giúp DropDownList được sử dụng trong các tình huống khác, trong đó quy ước là bạn có một SelectList trong ViewData có cùng tên với thuộc tính trong mô hình của bạn. Điều này sẽ hoạt động chính xác:

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

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

Cảm ơn người bạn đời rất nhiều, trên tất cả các câu trả lời này làm việc cho tôi, bí quyết dont do tại sao nhưng nó đã làm
Lamin Sanneh

Cuối cùng! Sau nhiều giờ cố gắng, cuối cùng tôi đã tìm thấy "yêu cầu duy nhất" của bạn. Điều đó đã làm được.
SteveCav 14/09/16

2

Nếu chúng tôi không nghĩ rằng đây là một lỗi mà nhóm nên sửa, MSDN nên cải thiện tài liệu. Điều khó hiểu thực sự đến từ tài liệu nghèo nàn về điều này. Trong MSDN , nó giải thích tên tham số là,

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

Điều này chỉ có nghĩa là html cuối cùng mà nó tạo ra sẽ sử dụng tham số đó làm tên của đầu vào được chọn. Nhưng, nó thực sự có ý nghĩa nhiều hơn thế.

Tôi đoán nhà thiết kế giả định rằng người dùng sẽ sử dụng một mô hình chế độ xem để hiển thị danh sách thả xuống, cũng sẽ sử dụng bài đăng trở lại cùng một mô hình chế độ xem. Nhưng trong rất nhiều trường hợp, chúng tôi không thực sự tuân theo giả định đó.

Sử dụng ví dụ trên,

public class Person {
    public int Id { get; set; }
    public string Name { get; set; }
}

Nếu chúng ta làm theo giả định, chúng ta nên xác định một mô hình chế độ xem cho chế độ xem liên quan đến danh sách thả xuống này

public class PersonsSelectViewModel{
    public string SelectedPersonId,
    public List<SelectListItem> Persons;
}

Bởi vì khi đăng lại, chỉ giá trị đã chọn mới đăng lại, vì vậy nó giả sử nó sẽ đăng lại thuộc tính SelectedPersonId của mô hình, có nghĩa là tên tham số đầu tiên của Html.DropDownList phải là 'SelectedPersonId'. Vì vậy, nhà thiết kế nghĩ rằng khi hiển thị dạng xem mô hình trong dạng xem, thuộc tính SelectedPersonId của mô hình sẽ giữ giá trị mặc định của danh sách thả xuống đó. Thậm chí bạn nghĩ rằng Danh sách người <SelectListItem> của bạn đã đặt cờ Đã chọn để cho biết cái nào được chọn / mặc định, tml.DropDownList sẽ thực sự bỏ qua điều đó và xây dựng lại IEnumerable <SelectListItem> của chính nó và đặt mục mặc định / được chọn dựa trên tên.

Đây là mã từ 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);
}

Vì vậy, mã thực sự đã đi xa hơn, nó không chỉ cố gắng tìm kiếm tên trong mô hình mà còn trong dữ liệu xem, ngay khi tìm thấy nó, nó sẽ xây dựng lại selectList và bỏ qua Selected ban đầu của bạn.

Vấn đề là, trong nhiều trường hợp, chúng tôi không thực sự sử dụng nó theo cách đó. chúng tôi chỉ muốn đưa vào selectList với một / nhiều mục được chọn là true.

Tất nhiên giải pháp rất đơn giản, hãy sử dụng tên không có trong mô hình cũng như trong dữ liệu xem. Khi nó không thể tìm thấy kết quả phù hợp, nó sẽ sử dụng selectList ban đầu và Selected ban đầu sẽ bị ảnh hưởng.

Nhưng tôi vẫn nghĩ mvc nên cải thiện nó bằng cách thêm một điều kiện nữa

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

Bởi vì, nếu selectList ban đầu đã có một Selected, tại sao bạn lại bỏ qua điều đó?

Chỉ là suy nghĩ của tôi.


Đây thực sự là lời giải thích tốt nhất mà tôi đã đọc cho đến nay. Đã cứu tôi rất nhiều đau đầu. Tất cả những gì tôi phải làm là đặt giá trị của thuộc tính viewmodel và nó hoạt động. Cảm ơn.
Moses Machua 19/12/16

2

Mã trong bài đăng MVC 3 trước đó không hoạt động nhưng nó là một khởi đầu tốt. Tôi sẽ sửa nó. Tôi đã thử nghiệm mã này và nó hoạt động trong MVC 3 Razor C # Mã này sử dụng mẫu ViewModel để điền một thuộc tính trả về a List<SelectListItem>.

Lớp người mẫu

public class Product
{
    public string Name { get; set; }
    public decimal Price { get; set; }
}

Lớp ViewModel

using System.Web.Mvc;

public class ProductListviewModel
{
    public List<SelectListItem> Products { get; set; }
}

Phương pháp điều khiển

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

Quang cảnh

@model MvcApp.ViewModels.ProductListViewModel

@using (Html.BeginForm())
{
    @Html.DropDownList("Products", Model.Products)
}

Đầu ra HTML sẽ giống như

<select id="Products" name="Products">
    <option value="3">Product: Widget 10.00</option>
    <option value="4">Product: Gadget 5.95</option>
</select>

tùy thuộc vào cách bạn định dạng đầu ra. Tôi hi vọng cái này giúp được. Mã không hoạt động.


1
Điều này không thiết lập selectedtùy chọn.
Jess

Để đặt mục đã chọn bằng SelectListItem, hãy đặt thuộc tính Đã chọn thành true.
wayne.blackmon,

1

Đây dường như là một lỗi trong lớp SelectExtensions vì nó sẽ chỉ kiểm tra ViewData hơn là mô hình cho mục đã chọn. Vì vậy, mẹo là sao chép mục đã chọn từ mô hình vào bộ sưu tập ViewData dưới tên của thuộc tính.

Đây là câu trả lời tôi đã đưa ra trên các diễn đàn MVC, tôi cũng có một câu trả lời đầy đủ hơn trong một bài đăng trên blog sử dụng thuộc tính DropDownList của Kazi ...

Đưa ra một mô hình

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

và một mô hình xem cơ bản của

public class ArticleModel
{
     public Guid Id { get; set; }
     public string Name { get; set; }

     [UIHint("DropDownList")]
     public Guid ArticleType { get; set; }
}

Sau đó, chúng tôi viết một mẫu trình chỉnh sửa DropDownList như sau ..

<%@ 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()) %>

Điều này cũng sẽ hoạt động nếu bạn thay đổi ArticleType trong mô hình chế độ xem thành SelectListItem, mặc dù bạn phải triển khai trình chuyển đổi kiểu theo blog của Kazi và đăng ký nó để buộc chất kết dính coi đây là kiểu đơn giản.

Trong bộ điều khiển của bạn, chúng tôi có ...

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

Cảm ơn đã trả lời, tôi sẽ phải kiểm tra điều này.
blu

0

Vấn đề là hộp kéo thả không hoạt động giống như hộp danh sách, ít nhất là cách thiết kế ASP.NET MVC2 mong đợi: Một hộp kéo thả chỉ cho phép 0 hoặc một giá trị, vì hộp danh sách có thể có nhiều lựa chọn giá trị. Vì vậy, nghiêm ngặt với HTML, giá trị đó không nên nằm trong danh sách tùy chọn dưới dạng cờ "đã chọn", mà nằm trong chính đầu vào.

Xem ví dụ sau:

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

Kết hợp có tùy chọn được chọn, nhưng cũng có bộ thuộc tính giá trị của nó . Vì vậy, nếu bạn muốn ASP.NET MVC2 hiển thị một hộp kéo thả và cũng có một giá trị cụ thể được chọn (ví dụ, giá trị mặc định, v.v.), bạn nên cung cấp cho nó một giá trị trong kết xuất, như sau:

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

0

Trong ASP.NET MVC 3, bạn chỉ cần thêm danh sách của mình vào 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;

... và sau đó tham chiếu nó theo tên trong chế độ xem dao cạo của bạn ...

@Html.DropDownList("options")

Bạn không cần phải "sử dụng" danh sách theo cách thủ công trong lệnh gọi DropDownList. Làm theo cách này cũng đặt chính xác giá trị đã chọn cho tôi.

Tuyên bố từ chối trách nhiệm:

  1. Chưa thử điều này với công cụ xem biểu mẫu web, nhưng nó cũng sẽ hoạt động.
  2. Tôi chưa thử nghiệm điều này trong v1 và v2, nhưng nó có thể hoạt động.

0

Tôi đã cố gắng đạt được kết quả mong muốn, nhưng với một cách tiếp cận hơi khác. Trong danh sách thả xuống, tôi đã sử dụng Mô hình và sau đó tham chiếu đến nó. Không chắc đây có phải là thứ bạn đang tìm kiếm hay không.

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

Model.Matters.FeeStructures ở trên là id của tôi, có thể là giá trị của mặt hàng bạn nên chọn.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.