質問

MVC2.0でテンプレート化されたヘルパーを使用すると、ドロップダウンリストに項目を入力する方法を見つけることができませんでした。 [UIHint(BadgesDropDown)] 属性を使用していますが、MVCパターンに違反せずにリストアイテムを取得する方法は、コントローラーがViewDataに配置する必要がありますか? BadgesDropDown.ascx でヘルパーを呼び出して取得する必要がありますか?

今、私はに行きます:

BadgesDropDown.ascx

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

コントローラー

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

これは進むべき道ですか?

役に立ちましたか?

解決

MVC 2のすばらしい新しいメソッド...使用する場合、すべての属性データに依存します。

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

これを機能させるには、2つのオプションがあります。 UIHintがデータのソースを提供するか、コントローラーが提供する必要があります。 UIHintが行う場合、ドロップダウンに提供されるデータは修正されます。もう1つのオプションはコントローラーで、ドロップダウンデータを必要に応じて異なるデータセットに切り替えることができます。

関連するいくつかの例が見つかりました:

オタクディナー

[1]:codeclimber.net.nzおよびhow-to-create-a-dropdownlist-with-asp.net-mvcのsearcch   [2]:bradwilson.typepad.comおよびtemplates-part-5-master-page-templates

他のヒント

最近、このトピックについて多くの議論がありました。日付、日付範囲、複数選択チェックボックスリストで同様のロードブロッキングが発生します。あらゆる場所で、豊富なHTMLコントロールのセットを使用できます。子ViewModelsの概念を実験してきましたが、私が試した他のアプローチよりもソリューションがきれいだと思います。

基本的な概念は、カスタムEditorTemplateに密接に結合された小さなビューモデルを定義することです。

例では、単一の選択リストに固有の(子)ViewModelで開始します。

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

ドロップダウンを使用するビューモデルで、選択モデルを構成します(すべてビューモデルを使用していますか?):

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

これは、ドロップダウンアイテムの固定セットを持つ単純な例です。ドメイン層から来ている場合、コントローラーはそれらをViewModelに渡します。

次に、Shared / EditorTemplatesにエディターテンプレートSelectModel.ascxを追加します

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

注:OptionForは明らかなことを行うカスタム拡張機能です

ここでのコツは、デフォルトのModelBinderが期待する複合形式を使用してIDと名前が設定されることです。この例では&quot; Priority.Value&quot;。したがって、SelectModelの一部として定義されている文字列ベースのValueプロパティは直接設定されます。フォームを再表示する必要がある場合、セッターは項目のリストを更新してデフォルトの選択オプションを設定します。

この「子ビューモデル」の場所アプローチが本当に輝くのは、より複雑な「マークアップのスニペットを制御する」ことです。 MultiSelectリスト、開始/終了の日付範囲、日付と時刻の組み合わせに対して同様のアプローチに従う子ビューモデルがあります。

この道を進むとすぐに、次の明らかな質問が検証になります。

すべての子ViewModelに標準インターフェースを実装させることになりました:

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

次に、カスタムValidationAttributeがあります:

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

これで、スカラープロパティのような子ViewModelベースのプロパティに属性を設定できます。

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

ソリューションを上記の例として実装しました。注意すべきことの1つは、ヘルパーは提供されたデータのみを使用する必要があることです。依存関係を表示

  

ベストプラクティスは、Htmlを記述することです   コントローラーを知らないヘルパーと   コンテキスト。彼らは仕事をするべきです   提供されるデータのみに基づく   呼び出し元。

上記の声明に同意します。通常のASP.Net開発と比較すると、多くの作業を行う必要があるだけです。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top