6

私は ASP.NET MVC で最初のサイトを作成中です。しかし、解決策が見つからないという問題にぶつかりました。

ユーザーが曲とタグを付けたアルバムを作成できるようにしたい。それは曲とタグの不特定の数である可能性があります。ただし、最低 5 つの曲と 2 つのタグが必要です。

しかし、モデルを通じてこれを可能にする方法を理解することはできません。

public class AlbumCreateModel
{
    [Required]
    [DisplayName("Title")]
    public string Title { get; set; }

    [DisplayName("Description")]
    public string Description { get; set; }

    [DisplayName("Publish")]
    public bool Public { get; set; }

    [DisplayName("Tags")]
    // Min 2 tags no max
    public List<AlbumTagModel> Tags { get; set; }

    [DisplayName("Songs")]
    // Min 5 songs no max
    public List<AlbumSongModel> Songs { get; set; }
}

public class AlbumTagModel
{
    [Required]
    [DisplayName("Tag")]
    // Regex to test no spaces
    // min 2 characters
    // maximum 15 characters
    public string Tag { get; set; }
}

public class AlbumSongModel
{
    [Required]
    [DisplayName("Title")]
    public string Title { get; set; }

    [Required]
    [DisplayName("Artist")]
    public string Artist { get; set; }

    [DisplayName("Description")]
    public string Description { get; set; }

    [DisplayName("Song Length")]
    public double Length { get; set; }

    [DisplayName("Year")]
    public int Description { get; set; }
}

意見:

<%@ Page Title="" Language="C#" MasterPageFile="~/App/Views/Shared/MasterPage.Master" Inherits="System.Web.Mvc.ViewPage<album.App.Models.AlbumCreateModel>" %>

<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">
    Create
</asp:Content>

<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
    <% using (Html.BeginForm()) { %>
        <%: Html.ValidationSummary(true, "Committing the album was unsuccessful. Please correct the errors and try again.")%>
        <div>
            <fieldset>
                <legend>Album Information</legend>

                <div class="editor-label">
                    <%: Html.LabelFor(m => m.Title) %>
                </div>
                <div class="editor-field">
                    <%: Html.TextBoxFor(m => m.Title)%>
                    <%: Html.ValidationMessageFor(m => m.Title)%>
                </div>

                <div class="editor-label">
                    <%: Html.LabelFor(m => m.Description) %>
                </div>
                <div class="editor-field">
                    <%: Html.TextAreaFor(m => m.Description)%>
                    <%: Html.ValidationMessageFor(m => m.Description)%>
                </div>

                <!-- Tags here -->

                <!-- Songs here -->

                <p>
                    <input type="submit" value="Commit" />
                </p>
            </fieldset>
        </div>
    <% } %>
</asp:Content>

<asp:Content ID="Content3" ContentPlaceHolderID="MetaData" runat="server">
</asp:Content>

考えられる解決策:

モデル:

public class PlaylistModel
    {
        [Required]
        [DisplayName("Title")]
        public string Title { get; set; }

        [DisplayName("Description")]
        public string Description { get; set; }

        [DisplayName("Publish")]
        public bool Public { get; set; }

        [DisplayName("Tags")]
        [ListCount(Min = 2)]
        // Min 2 tags no max
        public List<PlaylistTagModel> Tags { get; set; }

        [DisplayName("Songs")]
        [ListCount(Min = 5)]
        public List<PlaylistSongModel> Songs { get; set; }
    }

    public class PlaylistTagModel
    {
        [Required]
        [DisplayName("Tag")]
        // Regex to test no spaces
        // min 2 characters
        // maximum 15 characters
        public string Tag { get; set; }
    }

    public class PlaylistSongModel
    {
        [Required]
        [DisplayName("Title")]
        public string Title { get; set; }

        [Required]
        [DisplayName("Artist")]
        public string Artist { get; set; }

        [DisplayName("Description")]
        public string Description { get; set; }

        [DisplayName("Song Length")]
        public int Length { get; set; }

        [DisplayName("Year")]
        public int Year { get; set; }
    }

意見:

<%@ Page Title="" Language="C#" MasterPageFile="~/App/Views/Shared/MasterPage.Master" Inherits="System.Web.Mvc.ViewPage<playlist.App.Models.PlaylistModel>" %>

<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">
    Create
</asp:Content>

<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
    <% using (Html.BeginForm()) { %>
        <%: Html.ValidationSummary(true, "Committing the playlist was unsuccessful. Please correct the errors and try again.")%>
        <div>
            <fieldset>
                <legend>Playlist Information</legend>

                <div class="editor-label">
                    <%: Html.LabelFor(m => m.Title) %>
                </div>
                <div class="editor-field">
                    <%: Html.TextBoxFor(m => m.Title)%>
                    <%: Html.ValidationMessageFor(m => m.Title)%>
                </div>

                <div class="editor-label">
                    <%: Html.LabelFor(m => m.Description) %>
                </div>
                <div class="editor-field">
                    <%: Html.TextAreaFor(m => m.Description)%>
                    <%: Html.ValidationMessageFor(m => m.Description)%>
                </div>

                <br />
                <%: Html.ValidationMessageFor(m => m.Tags)%>
                <div class="editor-label">
                    <%: Html.LabelFor(m => m.Tags)%>
                </div>
                <div class="editor-field">
                    <%: Html.EditorFor(m => m.Tags) %>
                    <%: Html.Editor("Tags[" + (Model == null ? 0 : Model.Tags.Count) + "]", "PlaylistTagModel")%>
                </div>

                <br />
                <%: Html.ValidationMessageFor(m => m.Songs)%>
                <div class="editor-label">
                    <%: Html.LabelFor(m => m.Songs)%>
                </div>
                <div class="editor-field">
                    <%: Html.EditorFor(m => m.Songs)%>
                    <%: Html.Editor("Songs[" + (Model == null ? 0 : Model.Songs.Count) + "]", "PlaylistSongModel")%>
                </div>

                <p>
                    <input type="submit" value="Commit" />
                </p>
            </fieldset>
        </div>
    <% } %>
</asp:Content>

<asp:Content ID="Content3" ContentPlaceHolderID="MetaData" runat="server">
</asp:Content>

2 つのテンプレート:

<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<playlist.App.Models.PlaylistSongModel>" %>

<fieldset>
    <legend>Song Information</legend>
    <%: Html.ValidationSummary(true, "Committing this song was unsuccessful. Please correct the errors and try again.")%>

    <div class="editor-label">
        <%: Html.LabelFor(m => m.Title) %>
    </div>
    <div class="editor-field">
        <%: Html.TextBoxFor(m => m.Title)%>
        <%: Html.ValidationMessageFor(m => m.Title)%>
    </div>

    <div class="editor-label">
        <%: Html.LabelFor(m => m.Artist)%>
    </div>
    <div class="editor-field">
        <%: Html.TextBoxFor(m => m.Artist)%>
        <%: Html.ValidationMessageFor(m => m.Artist)%>
    </div>

    <div class="editor-label">
        <%: Html.LabelFor(m => m.Description)%>
    </div>
    <div class="editor-field">
        <%: Html.TextAreaFor(m => m.Description)%>
        <%: Html.ValidationMessageFor(m => m.Description)%>
    </div>

    <div class="editor-label">
        <%: Html.LabelFor(m => m.Length)%>
    </div>
    <div class="editor-field">
        <%: Html.TextBoxFor(m => m.Length)%>
        <%: Html.ValidationMessageFor(m => m.Length)%>
    </div>

    <div class="editor-label">
        <%: Html.LabelFor(m => m.Year)%>
    </div>
    <div class="editor-field">
        <%: Html.TextBoxFor(m => m.Year)%>
        <%: Html.ValidationMessageFor(m => m.Year)%>
    </div>
</fieldset>

鬼ごっこ:

<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<playlist.App.Models.PlaylistTagModel>" %>

<span class="tag"><%: Html.TextBoxFor(m => m.Tag)%></span> <%: Html.ValidationMessageFor(m => m.Tag)%>

そして最後にリストへの私のカスタムバリデータ:

public class ListCountAttribute : ValidationAttribute
    {
        public int Min { get; set; }
        public int Max { get; set; }

        public override bool IsValid(object value)
        {
            if (Min == 0 && Max == 0)
                return true;

            if (value == null)
                return false;

            if (!(value is ICollection))
                throw new InvalidOperationException("ListCountAttribute requires underlying property to implement ICollection");

            ICollection countable = value as ICollection;
            if (Min == 0 && Max != 0)
                return countable.Count <= Max;
            else if (Max == 0 && Min != 0)
                return countable.Count >= Min;
            return (countable.Count >= Min) && (countable.Count <= Max);
        }

        public override string FormatErrorMessage(string name)
        {
            if (Min == 0 && Max != 0)
                return "The field set " + name + " can not be larger then " + Max;
            else if (Max == 0 && Min != 0)
                return "The field set " + name + " need to have atleast a count of " + Min;
            return "The field set " + name + " need to between or equal to " + Min + " and " + Max;
        }
    }
4

3 に答える 3

7

/views/shared に「EditorTemplates」というフォルダーを作成します。まさにこれと呼ばなければなりません。

このフォルダーに、それぞれのモデルに厳密に型指定された AlbumTagModel.ascx および AlbumSongModel.ascx というファイルを作成します。

これらのファイルに入力フィールドを追加しますが、フォーム タグでラップしないでください。

ビューページに戻ります:

<%: Html.EditorFor(m => m.Tags)%>

<%: Html.EditorFor(m => m.Songs)%>

さあ、ほら!

入力タグをレンダリングすると、リストに一致するように添字が付けられます。EditorFor単独でループしてレンダリングします。厳密に型指定された AlbumViewModel を投稿すると、リストは元の位置に正しくバインドされます。

新しい曲/タグを追加するには、次を AlbumViewModel に追加します。

public AlbumTagModel NewTagModel {get;set;}

そのための追加の EditorFor() を追加します。

NewTagModel が有効な場合にモデルが投稿されたら、それをリストに追加してビューを再表示します。

于 2010-08-14T20:37:08.970 に答える
1

その要件をサポートするには、カスタム検証属性を記述する必要があります。

これはまさにあなたが探しているものではありませんが、正しい方向に向けられるはずの例です。その後に、環境に合わせて調整する方法についての注記があります。

public class AtLeastOneRequiredAttribute : ValidationAttribute
{
  public override bool IsValid(object value)
  {
    if (value == null)
      return false;

    if (!(value is ICountable))
      throw new InvalidOperationException("AtLeastOneRequiredAttribute requires underlying property to implement ICountable");

    ICountable countable = value as ICountable;
    return countable.Count >= 1;
  }
}

汎用リストの代わりに独自の「子モデル」を使用し、環境内のユーティリティ インターフェイスである ICountable を実装します。値が IList を実装していることを確認してから、 を呼び出すだけ(value as IList).Countです。

「少なくとも 1 つ」ではなく一般的な最小値については、最小プロパティを定義します。

他の質問がある場合は投稿してください。

于 2010-08-14T20:27:56.450 に答える
0

オブジェクトのコレクションを編集するためにテンプレート エディターを使用しようとすると、うまくいかないようです。ここに私が持っているものがあります:

public class Candidate
    {
        public Candidate()
        {
            this.References = new List<Reference>();
        }
        public int Id { get; set; }
        public string Name { get; set; }
        public DateTime? DateOfBirth { get; set; }
        [UIHint("Reference")]  
        public List<Reference> References { get; set; }

    }

public class Reference
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public string Institution { get; set; }
        public string Email { get; set; }
        public string Phone { get; set; }
        public string Position { get; set; }
    }

Views/Shared/TemplateEditors にテンプレートを作成し、厳密に型指定された部分ビュー Register.ascx を作成しました。

<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<Models.Reference>" %>
<%:Html.TextBoxFor(model=>model.Name) %>
<%:Html.TextBoxFor(model=>model.Email) %>
<%:Html.TextBoxFor(model=>model.Institution) %>
<%:Html.TextBoxFor(model=>model.Position) %>
<%:Html.TextBoxFor(model=>model.Phone) %>

候補があるというビューでは、以下のコードを使用して参照のリストをレンダリングします。

 <%: Html.EditorFor(m => m.References)%>

プロジェクトを実行すると、

 InvalidOperationException: The model item passed into the dictionary is of type 'System.Collections.Generic.List`1[Models.Reference]', but this dictionary requires a model item of type 'Models.Reference'.

実装に何か問題があると思いますか?

ありがとう。

于 2010-10-20T17:43:44.263 に答える