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.