Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/jquery/88.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 动态页面上的ASP.NET MVC 2验证_C#_Jquery_.net_Asp.net Mvc 2_Asp.net Mvc Validation - Fatal编程技术网

C# 动态页面上的ASP.NET MVC 2验证

C# 动态页面上的ASP.NET MVC 2验证,c#,jquery,.net,asp.net-mvc-2,asp.net-mvc-validation,C#,Jquery,.net,Asp.net Mvc 2,Asp.net Mvc Validation,我的asp.net mvc 2应用程序上有多个页面的注册向导。在第一页,我应该有参与该过程的人员的基本数据表。我应该有3个文本框标记为名字,姓氏和地址,和1个复选框与文字“添加另一个人”。当用户单击单选按钮时,新的文本框将显示新的单选按钮,因此我们可以在同一表单中添加多个人。理论上,我们应该能够尽可能多地插入人员。所有字段都是必填字段,因此在页面顶部的验证摘要中,我应该有类似“请输入第二个人的名字”之类的内容。我要上课了: public class Person { public st

我的asp.net mvc 2应用程序上有多个页面的注册向导。在第一页,我应该有参与该过程的人员的基本数据表。我应该有3个文本框标记为名字,姓氏和地址,和1个复选框与文字“添加另一个人”。当用户单击单选按钮时,新的文本框将显示新的单选按钮,因此我们可以在同一表单中添加多个人。理论上,我们应该能够尽可能多地插入人员。所有字段都是必填字段,因此在页面顶部的验证摘要中,我应该有类似“请输入第二个人的名字”之类的内容。我要上课了:

public class Person
{
     public string FullName { get; set; }
     public string LastName { get; set; }
     public string Address{ get; set; }
}
我假设我的页面模型应该是
List
,我会用javascript/jQuery为新人添加html。请在此帮助我,我应该如何验证此动态页面?我可以使用“保存”和“返回”按钮浏览这个向导,而且,我们应该能够松开页面上的任何单选按钮,该特定的人应该消失,验证器应该不再捕捉它。我的整个向导都在使用服务器端验证(DataAnnotations),我不想使用客户端验证。提前谢谢

更新:

我需要更多的帮助。我想用新属性扩展Person类:

public int Percent { get; set; } 
如果
IEnumerable
中每个人的所有百分比之和等于100,我希望在提交时进行服务器验证。我可以为此创建自定义属性吗?如何创建?我的模型是通用列表,我不能在上面应用
[CustomAttribute]
,对吗?

此外,我应该在页面顶部有验证摘要,而不是在每个输入之后。我已经提出:
有没有办法为每个人设置不同的验证消息?谢谢

在开始执行这项任务之前,我强烈建议您阅读史蒂文·桑德森的文章

准备好了吗

好的,现在我们可以开始实施了

第一件事是为任务定义我们的视图模型。您已经拥有了它,只需在其上定义相应的验证规则:

public class Person
{
    [Required]
    public string FullName { get; set; }

    [Required]
    public string LastName { get; set; }

    [Required]
    public string Address{ get; set; }
}
我想这个页面的模型应该是List

是的,绝对是

因此,让我们继续创建我们的
PersonController

public class PersonsController : Controller
{
    public ActionResult Index()
    {
        var model = new[] 
        {
            new Person()
        };
        return View(model);
    }

    [HttpPost]
    public ActionResult Index(IEnumerable<Person> persons)
    {
        if (!ModelState.IsValid)
        {
            return View(persons);
        }

        // To do: do whatever you want with the data
        // In this example I am simply dumping it to the output
        // but normally here you would update your database or whatever
        // and redirect to the next step of the wizard
        return Content(string.Join(Environment.NewLine, persons.Select(p => string.Format("name: {0} address: {1}", p.FullName, p.Address))));
    }

    public ActionResult BlankEditorRow()
    {
        return PartialView("_PersonEditorRow", new Person());
    }
}
以及相应的局部视图(
~/Views/persones/\u PersonEditorRow.cshtml
):


更新:

我的错,我刚刚注意到你的问题被标记为
asp.net-mvc-2
。所以我想我的观点不适用于你的情况。不过,其他一切都应该是一样的。您只需更新视图,使其使用WebForms视图引擎:

下面是
~/Views/Persons/Index.aspx

<%@ Page Language="C#" Inherits="System.Web.Mvc.ViewPage<IEnumerable<Person>>" %>
<% using (Html.BeginForm()) { %>
    <div id="editorRows">
        <% foreach (var item in Model) { %>
            <% Html.RenderPartial("_PersonEditorRow", item); %>
        <% } %>
    </div>    

    <%= Html.ActionLink(
        "Add another person", 
        "BlankEditorRow", 
        null, 
        new { id = "addItem" }
    ) %>

    <p>
        <button type="submit">Next step</button>
    </p>
<% } %>

<script type="text/javascript">
    $('#addItem').click(function () {
        $.ajax({
            url: this.href,
            cache: false,
            success: function (html) { $('#editorRows').append(html); }
        });
        return false;
    });

    $(document).delegate('a.deleteRow', 'click', function () {
        $(this).parents('div.editorRow:first').remove();
        return false;
    });
</script>

谢谢,达林,这个很好用。我需要更多帮助。我想用新属性扩展Person类:
public int Percent{get;set;}
,如果IEnumerable中每个人的所有百分比之和等于100,我想在提交时进行服务器验证。我可以为此创建自定义属性吗?如何创建?我的模型是通用列表,我不能在上面应用[CustomAttribute],对吗?而且,我应该在页面顶部有验证摘要,而不是在每个输入之后。我已经提出:
有没有办法为每个人设置不同的验证消息?谢谢
@model Person

<div class="editorRow">
    @using(Html.BeginCollectionItem("persons")) 
    {
        <div>
            @Html.LabelFor(x => x.FullName)
            @Html.EditorFor(x => x.FullName)
            @Html.ValidationMessageFor(x => x.FullName)
        </div>
        <div>
            @Html.LabelFor(x => x.LastName)
            @Html.EditorFor(x => x.LastName)
            @Html.ValidationMessageFor(x => x.LastName)
        </div>
        <div>
            @Html.LabelFor(x => x.Address)
            @Html.EditorFor(x => x.Address)
            @Html.ValidationMessageFor(x => x.Address)
        </div>

        <a href="#" class="deleteRow">delete</a>
    }
</div>
public static class HtmlPrefixScopeExtensions
{
    private const string idsToReuseKey = "__htmlPrefixScopeExtensions_IdsToReuse_";

    public static IDisposable BeginCollectionItem(this HtmlHelper html, string collectionName)
    {
        var idsToReuse = GetIdsToReuse(html.ViewContext.HttpContext, collectionName);
        string itemIndex = idsToReuse.Count > 0 ? idsToReuse.Dequeue() : Guid.NewGuid().ToString();

        // autocomplete="off" is needed to work around a very annoying Chrome behaviour whereby it reuses old values after the user clicks "Back", which causes the xyz.index and xyz[...] values to get out of sync.
        html.ViewContext.Writer.WriteLine(string.Format("<input type=\"hidden\" name=\"{0}.index\" autocomplete=\"off\" value=\"{1}\" />", collectionName, html.Encode(itemIndex)));

        return BeginHtmlFieldPrefixScope(html, string.Format("{0}[{1}]", collectionName, itemIndex));
    }

    public static IDisposable BeginHtmlFieldPrefixScope(this HtmlHelper html, string htmlFieldPrefix)
    {
        return new HtmlFieldPrefixScope(html.ViewData.TemplateInfo, htmlFieldPrefix);
    }

    private static Queue<string> GetIdsToReuse(HttpContextBase httpContext, string collectionName)
    {
        // We need to use the same sequence of IDs following a server-side validation failure,  
        // otherwise the framework won't render the validation error messages next to each item.
        string key = idsToReuseKey + collectionName;
        var queue = (Queue<string>)httpContext.Items[key];
        if (queue == null)
        {
            httpContext.Items[key] = queue = new Queue<string>();
            var previouslyUsedIds = httpContext.Request[collectionName + ".index"];
            if (!string.IsNullOrEmpty(previouslyUsedIds))
                foreach (string previouslyUsedId in previouslyUsedIds.Split(','))
                    queue.Enqueue(previouslyUsedId);
        }
        return queue;
    }

    private class HtmlFieldPrefixScope : IDisposable
    {
        private readonly TemplateInfo templateInfo;
        private readonly string previousHtmlFieldPrefix;

        public HtmlFieldPrefixScope(TemplateInfo templateInfo, string htmlFieldPrefix)
        {
            this.templateInfo = templateInfo;

            previousHtmlFieldPrefix = templateInfo.HtmlFieldPrefix;
            templateInfo.HtmlFieldPrefix = htmlFieldPrefix;
        }

        public void Dispose()
        {
            templateInfo.HtmlFieldPrefix = previousHtmlFieldPrefix;
        }
    }
}
<%@ Page Language="C#" Inherits="System.Web.Mvc.ViewPage<IEnumerable<Person>>" %>
<% using (Html.BeginForm()) { %>
    <div id="editorRows">
        <% foreach (var item in Model) { %>
            <% Html.RenderPartial("_PersonEditorRow", item); %>
        <% } %>
    </div>    

    <%= Html.ActionLink(
        "Add another person", 
        "BlankEditorRow", 
        null, 
        new { id = "addItem" }
    ) %>

    <p>
        <button type="submit">Next step</button>
    </p>
<% } %>

<script type="text/javascript">
    $('#addItem').click(function () {
        $.ajax({
            url: this.href,
            cache: false,
            success: function (html) { $('#editorRows').append(html); }
        });
        return false;
    });

    $(document).delegate('a.deleteRow', 'click', function () {
        $(this).parents('div.editorRow:first').remove();
        return false;
    });
</script>
<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<Person>" %>
<div class="editorRow">
    <% using(Html.BeginCollectionItem("persons")) { %>
        <div>
            <%= Html.LabelFor(x => x.FullName) %>
            <%= Html.EditorFor(x => x.FullName) %>
            <%= Html.ValidationMessageFor(x => x.FullName) %>
        </div>
        <div>
            <%= Html.LabelFor(x => x.LastName) %>
            <%= Html.EditorFor(x => x.LastName) %>
            <%= Html.ValidationMessageFor(x => x.LastName) %>
        </div>
        <div>
            <%= Html.LabelFor(x => x.Address) %>
            <%= Html.EditorFor(x => x.Address) %>
            <%= Html.ValidationMessageFor(x => x.Address) %>
        </div>

        <a href="#" class="deleteRow">delete</a>
    <% } %>
</div>