3

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

これは行く方法ですか?

4

3 に答える 3

2

最近、このトピックについて多くの議論がありました。日付、日付範囲、および複数選択チェックボックス リストでも、同様の障害が発生します。html コントロールの豊富なセットを使用したい場所ならどこでも。私は子ViewModelの概念を試してきましたが、解決策は私が試した他のアプローチよりもきれいだと思います.

基本的な概念は、カスタム 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 に渡します。

次に、エディター テンプレート SelectModel.ascx を 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>

注: OptionFor は、明白な機能を実行するカスタム拡張機能です。

ここでの秘訣は、デフォルトの ModelBinder が期待する複合形式を使用して ID と名前を設定することです。この例では、「Priority.Value」です。そのため、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; }
于 2010-06-29T04:40:09.390 に答える
0

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 の検索 [2]: bradwilson.typepad.com および templates-part-5-master-page-templates

于 2009-11-09T00:36:42.573 に答える
-1

上記の例のようにソリューションを実装しました。注意すべきことの 1 つは、ヘルパーは提供されたデータでのみ動作する必要があることです。ビューの依存関係を参照してください。

ベスト プラクティスは、コントローラーとコンテキストを認識しない Html ヘルパーを作成することです。呼び出し元から提供されたデータのみに基づいてジョブを実行する必要があります。

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

于 2009-11-06T12:16:01.353 に答える