MVC Templated Helper - DropDown
-
10-07-2019 - |
Frage
die Templat Helfer Verwendung in MVC2.0 ich in ein dillema lief, wie die Einzelteile zu erhalten, eine Dropdownlist zu füllen.
Ich bin mit einem [UIHint(BadgesDropDown)]
Attribute, aber wie werde ich die Listenelemente erhalten, ohne die MVC-Muster zu verletzen, sollte den Controller Ort, um sie in der Viewdata? Sollte der BadgesDropDown.ascx
einen Helfer aufgerufen, sie zu erhalten?
Im Moment bin ich gehen für:
BadgesDropDown.ascx
<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl" %>
<%= Html.DropDownList("", ViewData["Badges"] as IEnumerable<SelectListItem>)%>
Controller
ViewData["Badges"] = new SelectList(SiteRepository.GetBadges(), "RowKey", "BadgeName");
Ist dies der Weg zu gehen?
Lösung
In der MVC 2 eine große neue Methode ... die, wenn verwendet, stützt sich auf die alle Attributdaten.
<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master"
Inherits="System.Web.Mvc.ViewPage<glossaryDB.EntityClasses.AssociationEntity>" %>
<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">
Association: Edit
</asp:Content>
<asp:Content ID="Content3" ContentPlaceHolderID="MainContent" runat="server">
<h3>Association: Edit</h3>
<% using (Html.BeginForm()) { %>
<fieldset style="padding: 1em; margin: 0; border: solid 1px #999;">
<%= Html.ValidationSummary("Edit was unsuccessful. Please correct the errors and try again.") %>
<%= Html.EditorForModel() %>
<input type="submit" value=" Submit " />
</fieldset>
<% } %>
<p><%= Html.ActionLink("Details", "Index") %></p>
</asp:Content>
Für diese dort zu arbeiten sind 2 Möglichkeiten. Entweder die UIHint hat, die Quelle der Daten zu liefern, oder die Steuerung muss. Wenn die UIHint tut dann den zu thhe Drop-Down zur Verfügung gestellten Daten festgelegt. Die andere Option ist die Steuerung, die uns die Drop-Down-Daten mit einem anderen Satz von Daten zu wechseln heraus ermöglicht als reqired.
Es gibt einige relevante Beispiele, die ich gefunden:
Nerd-Dinner
[1]: searcch für codeclimber.net.nz und How-to-create-a-Dropdownlist-mit-asp.net-mvc [2]: bradwilson.typepad.com und Vorlagen-Teil-5-Master-Seite-Vorlagen
Andere Tipps
Es gab in letzter Zeit viele Diskussionen über dieses Thema. Ähnliche Straßensperren sind mit Terminen, Datumsbereichen und Multi-Select-Checkbox Listen festgestellt. Überall möchten Sie vielleicht einen umfangreichen Satz von HTML-Steuerelemente verwenden. Ich habe mit dem Konzept der Kinderviewmodel zu experimentieren, und ich glaube, die Lösung ist sauberer als andere Ansätze, die ich ausprobiert habe.
Das Grundkonzept ist, dass Sie einen kleinen Einblick Modell definieren, die auf eine benutzerdefinierte EditorTemplate eng gekoppelt ist.
In Ihrem Beispiel, würden wir mit einem (Kind) Ansichtsmodell beginnen, die eine einzelne Auswahlliste spezifischen ist:
public class SelectModel
{
#region SelectModel(string value, IEnumerable<SelectListItem> items)
public SelectModel(string value, IEnumerable<SelectListItem> items)
{
_value = value;
Items = new List<SelectListItem>(items);
_Select();
}
#endregion
// Properties
public List<SelectListItem> Items { get; private set; }
public string Value
{
get { return _value; }
set { _value = value; _Select();}
}
private string _value;
// Methods
private void _Select()
{
Items.ForEach(x => x.Selected = (Value != null && x.Value == Value));
}
}
In der Ansicht Modell, das die Dropdown-Liste verwenden möchte, dass Sie das Modell auswählen komponieren (wir sind alle Ansicht Modelle verwenden, oder?):
public class EmailModel
{
// Constructors
public EmailModel()
{
Priority = new SelectModel("normal", _ToPrioritySelectItems());
}
// Properties
public SelectModel Priority { get; set; }
// Methods
private IEnumerable<SelectListItem> _ToPrioritySelectItems()
{
List<SelectListItem> result = new List<SelectListItem>();
result.Add(new SelectListItem() { Text = "High", Value = "high" });
...
}
Hinweis: Dies ist ein einfaches Beispiel mit einem festen Satz von Drop-Down-Elementen. Wenn sie aus der Domäne Schicht kommen, die Steuerung übergibt sie in das Ansichtsmodell.
Dann eine Editor Vorlage SelectModel.ascx fügt in Geteilt / EditorTemplates
<%@ Control Inherits="System.Web.Mvc.ViewUserControl<SelectModel>" %>
<div class="set">
<%= Html.LabelFor(model => model) %>
<select id="<%= ViewData.ModelMetadata.PropertyName %>_Value" name="<%=ViewData.ModelMetadata.PropertyName %>.Value">
<% foreach (var item in Model.Items) { %>
<%= Html.OptionFor(item) %>
<% } %>
</select>
</div>
Hinweis: OptionFor ist eine kundenspezifische Erweiterung, die die offensichtlich funktioniert
Der Trick hier ist, dass die ID und der Name gesetzt, um die Verbindung Format verwenden, das die Standard-Modelbinder erwartet. In unserem Beispiel "Priority.Value". So ist die Zeichenfolge basierend Value-Eigenschaft, die als Teil SelectModel definiert ist, wird direkt eingestellt. Der Setter kümmert sich um die Liste der Elemente Aktualisieren der Standard wählen Sie die Option setzen, wenn wir das Formular erneut anzuzeigen benötigen.
Wo dieses „Kind View-Modell“ -Ansatz wirklich glänzt ist komplexer „Steuerauszüge Markup“. Ich jetzt untergeordnete Ansicht Modelle, die einen ähnlichen Ansatz für Multiselect-Listen, Start / Ende Datumsbereiche und Datum + Zeit-Kombinationen folgen.
Sobald Sie diesen Weg gehen, die nächste offensichtliche Frage wird Validierung.
ich am Ende all mein Kind Ansichtsmodell ist mit implementieren eine Standardschnittstelle:
public interface IValidatable
{
bool HasValue { get; }
bool IsValid { get; }
}
Dann habe ich eine benutzerdefinierte Validation:
public class IsValidAttribute : ValidationAttribute
{
// Constructors
public IsValidAttribute()
{
ErrorMessage = "(not valid)";
}
// Properties
public bool IsRequired { get; set; }
// Methods
private bool Is(object value)
{
return value != null && !"".Equals(value);
}
public override bool IsValid(object value)
{
if (!Is(value) && !IsRequired)
return true;
if (!(value is IValidatable))
throw new InvalidOperationException("IsValidAttribute requires underlying property to implement IValidatable");
IValidatable validatable = value as IValidatable;
return validatable.IsValid;
}
}
Jetzt können Sie nur Attribute auf Eigenschaften setzen, die Kind sind Ansichtsmodell basiert wie jedes skalare Eigenschaft:
[IsValid(ErrorMessage = "Please enter a valid start date/time")]
public DateAndTimeModel Start { get; set; }
Ich implementierte die Lösung, wie das obige Beispiel. Eine Sache ist zu beachten, dass Helfer nur mit den gelieferten Daten, um sie funktionieren sollte, finden Sie unter Ansicht Abhängigkeit
Die beste Praxis ist Html zu schreiben Helfer nicht bewusst von Controllern und Kontexten. Sie sollten ihre Arbeit tun nur basierend auf welche Daten geliefert wird der Anrufer.
Ich bin damit einverstanden auf die obige Aussage. Es ist nur so, dass eine Menge Arbeit getan werden muss, wenn sie auf die regelmäßige ASP.Net Entwicklung verglichen.