Wenn wir nicht glauben, dass dies ein Fehler ist, den das Team beheben sollte, sollte MSDN das Dokument zumindest verbessern. Das Verwirrende kommt wirklich von dem schlechten Dokument davon. In MSDN wird der Name des Parameters wie folgt erläutert :
Type: System.String
The name of the form field to return.
Dies bedeutet nur, dass das endgültige HTML, das es generiert, diesen Parameter als Namen der Auswahleingabe verwendet. Aber es bedeutet tatsächlich mehr als das.
Ich denke, der Designer geht davon aus, dass der Benutzer ein Ansichtsmodell verwendet, um die Dropdown-Liste anzuzeigen, und auch den Post zurück zu derselben verwendet Ansichtsmodell verwendet. In vielen Fällen folgen wir dieser Annahme jedoch nicht wirklich.
Verwenden Sie das obige Beispiel,
public class Person {
public int Id { get; set; }
public string Name { get; set; }
}
Wenn wir der Annahme folgen, sollten wir ein Ansichtsmodell für diese Dropdown-Liste definieren
public class PersonsSelectViewModel{
public string SelectedPersonId,
public List<SelectListItem> Persons;
}
Denn wenn Post zurück, nur der ausgewählte Wert Post zurück wird, so dass er es annehmen sollte das Modell der Eigenschaft SelectedPersonId Post zurück, die Html.DropDownList erster Parameter bedeutet Name soll ‚SelectedPersonId‘ sein. Der Designer ist daher der Ansicht, dass beim Anzeigen der Modellansicht in der Ansicht die Modelleigenschaft SelectedPersonId den Standardwert dieser Dropdown-Liste enthalten sollte. Obwohl Ihre List <SelectListItem> -Personen bereits das Flag Selected gesetzt haben, um anzugeben, welche ausgewählt / standardmäßig ist, ignoriert die tml.DropDownList dies tatsächlich und erstellt ihre eigene IEnumerable <SelectListItem> neu und legt das Standard- / ausgewählte Element basierend auf dem Namen fest.
Hier ist der Code von 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);
}
Der Code ging also tatsächlich weiter und versuchte nicht nur, den Namen im Modell nachzuschlagen, sondern auch in den Ansichtsdaten. Sobald er einen findet, wird die selectList neu erstellt und Ihre ursprüngliche Selected ignoriert.
Das Problem ist, dass wir es in vielen Fällen nicht wirklich so verwenden. Wir wollen nur eine Auswahlliste mit einem / mehreren Elementen einwerfen. Ausgewählte Menge wahr.
Natürlich ist die Lösung einfach. Verwenden Sie einen Namen, der weder im Modell noch in den Ansichtsdaten enthalten ist. Wenn keine Übereinstimmung gefunden werden kann, wird die ursprüngliche Auswahlliste verwendet, und die ursprüngliche Auswahl wird wirksam.
Aber ich denke immer noch, dass mvc es verbessern sollte, indem es eine weitere Bedingung hinzufügt
if ((defaultValue != null) && (!selectList.Any(i=>i.Selected)))
{
selectList = GetSelectListWithDefaultValue(selectList, defaultValue, allowMultiple);
}
Denn wenn die ursprüngliche selectList bereits eine Selected hatte, warum sollten Sie das ignorieren?
Nur meine Gedanken.