ASP.NET MVC 2アレイ/リスト付きモデル
-
28-09-2019 - |
質問
私は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;
}
}
解決
「editortemplates」と呼ばれる /views /共有のフォルダーを作成します。これを正確に呼ぶ必要があります。
このフォルダーでは、それぞれのモデルに強く入力されたAlbumTagModel.ascxとAlbumSongModel.ascxというファイルを作成します。
これらのファイルの入力フィールドを追加しますが しない それらをフォームタグで包みます。
ビューに戻るページPUT:
<%: Html.EditorFor(m => m.Tags)%>
と
<%: Html.EditorFor(m => m.Songs)%>
今出来上がり!
レンダリングすると、入力タグがサブスクリプトに表示され、リストが一致します。 EditorFor
すべてのループとレンダリングを単独でレンダリングします。強く入力されたAblumViewModelを投稿すると、リストは正しく元のポジションに戻ります。
新しい曲/タグを追加するには、アルバムに以下を追加します。
public AlbumTagModel NewTagModel {get;set;}
追加のeditorfor()を追加します。
NewtagModelが有効な場合、モデルが投稿した場合、それをリストに追加し、ビューを再表示します。
他のヒント
その要件をサポートするには、カスタム検証属性を記述する必要があります。
これは、あなたが探しているものではなく、正しい方向に向けられるべきであるという例です。環境に合わせてどのように調整するかについてのメモがあります。
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;
}
}
一般的なリストの代わりに独自の「子モデル」を使用し、環境のユーティリティインターフェイスである象徴的なリストを実装してもらいます。あなたはあなたの価値がILISTを実装したことを確認するためにただチェックして、それから呼び出します (value as IList).Count
.
「少なくとも1つ」ではなく一般的な最小値については、最小プロパティを定義します。
それがあなたが正しい方向に向かっていることを願っています、あなたが他の質問があるならば、投稿してください。
オブジェクトのコレクションを編集するためにテンプレートエディターを使用しようとするとき、私はそれを機能させることができないようです。これが私が持っているものです:
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でテンプレートを作成し、強く型付けられたPartial View 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'.
実装に何か問題がありますか?
ありがとう。