Question

À l’aide des modèles proposés dans MVC2.0, j’ai rencontré un dillema, comment obtenir les éléments pour remplir une liste déroulante. J'utilise un attribut [UIHint (BadgesDropDown)] , mais comment vais-je obtenir les éléments de la liste sans violer le modèle MVC, le contrôleur doit-il les placer dans le ViewData? Le BadgesDropDown.ascx doit-il appeler un assistant pour les obtenir?

En ce moment, je vais pour:

BadgesDropDown.ascx

<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl" %>
<%= Html.DropDownList("", ViewData["Badges"] as IEnumerable<SelectListItem>)%>

Contrôleur

ViewData["Badges"] = new SelectList(SiteRepository.GetBadges(), "RowKey", "BadgeName");

Est-ce la voie à suivre?

Était-ce utile?

La solution

Dans le MVC 2, une nouvelle méthode géniale ... qui, si elle est utilisée, repose sur toutes les données d'attribut.

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

Pour que cela fonctionne, il y a 2 options. UIHint doit fournir la source des données ou le contrôleur doit. Si UIHint le fait, les données fournies au menu déroulant sont corrigées. L'autre option est le contrôleur, ce qui nous permet de désactiver les données de la liste déroulante avec un ensemble de données différent selon les besoins.

Il y a quelques exemples connexes que j'ai trouvés:

Dîner nerd

[1]: effectuer une recherche pour codeclimber.net.nz et comment créer une liste déroulante avec asp.net-mvc   [2]: bradwilson.typepad.com et templates-part-5-master-page-templates

Autres conseils

Il y a eu beaucoup de discussions sur ce sujet récemment. Des obstacles similaires se rencontrent avec des dates, des plages de dates et des listes de cases à cocher à sélections multiples. Partout où vous voudrez peut-être utiliser un riche ensemble de contrôles HTML. J'ai expérimenté le concept de ViewModels pour enfants et je pense que la solution est plus propre que les autres approches que j'ai essayées.

Le concept de base est que vous définissez un modèle de vue réduite étroitement couplé à un EditorTemplate personnalisé.

Dans votre exemple, nous commencerions par un ViewModel (enfant) spécifique à une liste de sélection unique:

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

Dans le modèle d'affichage qui souhaite utiliser le menu déroulant, vous composez le modèle sélectionné (nous utilisons tous des modèles d'affichage, non?):

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

Notez qu'il s'agit d'un exemple simple avec un ensemble fixe d'éléments déroulants. S'ils proviennent de la couche de domaine, le contrôleur les transmet au ViewModel.

Ajoutez ensuite un modèle d’éditeur SelectModel.ascx dans Shared / 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>

Remarque: OptionFor est une extension personnalisée qui fait la différence

.

Le truc, c’est que l’id et le nom sont définis en utilisant le format composé attendu par ModelBinder. Dans notre exemple, "Priority.Value". Ainsi, la propriété Value basée sur une chaîne définie dans le cadre de SelectModel est définie directement. Le configurateur se charge de mettre à jour la liste des éléments pour définir l'option de sélection par défaut si nous devons afficher à nouveau le formulaire.

Où ce " modèle de vue enfant " L’approche qui brille vraiment est plus complexe "contrôle des extraits de balises". J'ai maintenant des modèles de vue enfant qui suivent une approche similaire pour les listes MultiSelect, les plages de dates de début / fin et les combinaisons Date + heure.

Dès que vous empruntez ce chemin, la prochaine question évidente devient la validation.

J'ai finalement demandé à tous mes enfants ViewModel de mettre en œuvre une interface standard:

public interface IValidatable
{
  bool HasValue { get; }
  bool IsValid { get; }
}

Ensuite, j'ai un ValidationAttribute personnalisé:

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

Maintenant, vous pouvez simplement mettre des attributs sur des propriétés qui sont des enfants ViewModel, comme toute propriété scalaire:

[IsValid(ErrorMessage = "Please enter a valid start date/time")]
public DateAndTimeModel Start { get; set; }

J'ai implémenté la solution comme dans l'exemple ci-dessus. Une chose à noter est que les assistants ne doivent travailler qu'avec les données qui leur sont fournies, voir Afficher la dépendance

  

La meilleure pratique consiste à écrire du code HTML.   les aides ignorant des contrôleurs et   contextes. Ils devraient faire leur travail   uniquement en fonction des données fournies par   l'appelant.

Je suis d'accord sur la déclaration ci-dessus. C'est juste qu'il y a beaucoup de travail à faire par rapport au développement ASP.Net habituel.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top