带有数组/列表的 ASP.NET MVC 2 模型
我正在使用 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>
两个模板:
<%@ 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;
}
}
I am in the process of creating my first site in ASP.NET MVC, it is a kind of learn as you go. But I have hit a problem that I just can't find a solution for.
I want my user to be able to create an album with songs and tags attached.
That can be an unspecified number of songs and tags. But there must be a minimum of 5 songs and 2 tags.
But I can not figure out how to make this possible through the model, here is how far I have been able to get.
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; }
}
View:
<%@ 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>
A possible solution:
Model:
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; }
}
View:
<%@ 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>
The two templates:
<%@ 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>
Tag:
<%@ 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)%>
And finally my custom validator to lists:
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;
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
在 /views/shared 中创建一个名为“EditorTemplates”的文件夹。
它必须准确地称为这个。
在此文件夹中创建名为AlbumTagModel.ascx 和AlbumSongModel.ascx 的文件,并强类型化到各自的模型。
在这些文件中添加输入字段,但不要将它们包装在表单标签中。
返回您的视图页面,输入:
现在
瞧!
当您渲染输入标签时,将添加下标以匹配您的列表。
EditorFor
将自行循环并渲染所有内容。当您发布强类型的 AlbumViewModel 时,您的列表将正确绑定回其原始位置。
要添加新歌曲/标签,请将以下内容添加到您的AlbumViewModel:
并为其添加一个额外的EditorFor()。
当您的模型发布时,如果 NewTagModel 有效,则将其添加到列表中并重新显示视图。
Create a folder in /views/shared called "EditorTemplates".
It must be called this exactly.
In this folder create files called AlbumTagModel.ascx and AlbumSongModel.ascx strongly typed to their respective models.
Add the input fields in these files but do not wrap them in form tags.
Back in your view page put:
and
Now voila!
When you render the input tags will be subscripted to match your list.
EditorFor
will loop and render all by itself.When you post your strongly typed AlbumViewModel your lists will be correctly bound back to their original positions.
To add new songs/tags add the following to your AlbumViewModel:
and add an extra EditorFor() for it.
When your model posts if the NewTagModel is valid add it to the list and reshow the view.
您必须编写自定义验证属性来支持该要求。
这是一个并不完全是您正在寻找的示例,但应该可以为您指明正确的方向。其后有关于如何根据您的环境进行调整的注释。
我们使用自己的“子模型”而不是通用列表,并让它们实现 ICountable,这是我们环境中的实用程序接口。您只需检查以确保您的值实现了 IList,然后调用
(value as IList).Count
。对于一般最小值而不是“至少一个”,请定义最小值属性。
希望这能让您朝着正确的方向前进,如果您有其他问题,请留言。
You have to write a custom validation attribute to support that requirement.
Here's an example that isn't exactly what you're looking for, but should get you pointed in the right direction. There are notes after it on how you would adjust it for your environment.
We use our own "child models" instead of generic lists and have them implement ICountable, which is a utility interface in our environment. You would just check to make sure that your value implemented IList, then invoke
(value as IList).Count
.For a general minimum instead of the "At Least One", define a Min Property.
Hope that gets you headed in the right direction, post if you have other questions.
当尝试使用模板编辑器编辑对象集合时,我似乎无法使其工作。
这就是我所拥有的:
我在 Views/Shared/TemplateEditors 中创建了一个模板,并创建了一个强类型部分视图 Register.ascx。
鉴于我有候选人,我使用下面的代码来呈现参考文献列表。
当我运行该项目时,我发现
你们看到实施有什么问题吗?
谢谢。
I can't seem to make it work when trying to use template editors for editing a collection of objects.
Here's what I have:
I created a template in Views/Shared/TemplateEditors, and created a strongly typed partial view Register.ascx.
In the view that I have the candidate I use the code below to render the list of references.
When I run the project I get
Do you guys see anything wrong with the implementation?
Thanks.