MVC4添加嵌套列表

时间:2013-06-17 16:35:30

标签: asp.net-mvc

我有一个MainViewModel类,结构如下:

public class MainViewModel
{
       ...some properties
       private ObservableCollection<Strike> m_strikes;
    public ObservableCollection<Strike> Strikes
    {
        get
        {
            if (this.m_strikes == null)
                this.m_strikes = new ObservableCollection<Strike>();
            return this.m_strikes;
        }
    }
}
public class Strike
{
    private ObservableCollection<Reivindication> m_reivindications;
    public ObservableCollection<Reivindication> Reivindications
    {
        get { return m_reivindications; }
        set
        {
            m_reivindications = value;
            this.OnPropertyChanged("Reivindications");
        }
    }
private ObservableCollection<StrikeDate> m_stikeDates;
        public ObservableCollection<StrikeDate> StrikeDates
        {
            get { return m_stikeDates; }
            set
            {
                m_stikeDates = value;
                this.OnPropertyChanged("StrikeDates");
            }
        }      
    }

Reivindication和StrikeDates这些类有一些与该问题无关的属性。

我有部分视图呈现MainViewModel模型:

    @model Models.MainViewModel
<link rel="Stylesheet" href="../../Content/Site.css" type="text/css" />

<div class="content-wrapper">
    <img src="~/Images/someimage.png" height="300" style="position:absolute" />

    <section id="loginForm" style="position:relative;width:685px;height:600px;">
    @using (Html.BeginForm("Save", "Home", FormMethod.Post, new { ReturnUrl = ViewBag.ReturnUrl }))
    {
        @Html.HiddenFor(m => m.Id)
        <div style="position:relative;top:270px;" id="strikesDiV">
            @Ajax.ActionLink("Add Strike...","AddStrike","Home",
                new { containerPrefix = this.ViewData["ContainerPrefix"], @class="addStrikeItem"},
                new AjaxOptions { InsertionMode = InsertionMode.InsertAfter,HttpMethod = "POST", UpdateTargetId = "strikesDiV" }, 
                null)
            @foreach (Models.Strike strike in Model.Strikes)
            {
                Html.RenderPartial("_StrikePartial", strike);
            }
        </div>
        <input type="submit" class="k-button" value="Save" style="position:absolute; left:620px;top:0px;" />
    }
    </section>
</div>

我的_StrikePartial视图有:

    @using Report.Helpers
@model Models.Strike
<link rel="Stylesheet" href="../../Content/Site.css" type="text/css" />
<div class="editorRow" style="border-style:solid;border-width:1px;min-height:100px;overflow:auto;">
@using(Html.BeginCollectionItem("Strikes"))
{
    <text>Identification</text> @Html.TextBoxFor(m => m.Identification,  new {data_containerPrefix=this.ViewData["ContainerPrefix"]}) <a href="#" class="deleteRow">delete</a>  

    <div style="top:10px;" id="reivindicationsDiV">

            @Ajax.ActionLink("Add Reivindication...", "AddReivindication", "Home",
                new { containerPrefix = this.ViewData["ContainerPrefix"], @class="addReivindicationItem"},
                new AjaxOptions { InsertionMode = InsertionMode.InsertAfter, HttpMethod = "POST", UpdateTargetId = "reivindicationsDiV"},
                new { style = "float:right" })
            @foreach (Models.Reivindication reivindication in Model.Reivindications)
            {
                Html.RenderPartial("_ReivindicationPartial", reivindication);
            }
        </div>


    <div style="top:10px;" id="strikeDatesDiV">
        @Ajax.ActionLink("Add strike date...","AddStrikeDate","Home",
                new { containerPrefix = this.ViewData["ContainerPrefix"], @class="addStrikeDateItem"},
                new AjaxOptions { InsertionMode = InsertionMode.InsertAfter,HttpMethod = "POST", UpdateTargetId = "strikeDatesDiV" }, 
                new { style="float:right" })
            @foreach (Models.StrikeDate strikeDate in Model.StrikeDates)
            {
                Html.RenderPartial("_StrikeDatePartial", strikeDate);
            }
        </div>
}
</div>
<script>
    $("a.deleteRow").live("click", function () {
        $(this).parents("div.editorRow:first").remove();
        return false;
    });
</script>

和其中一个部分(_ReivindicationPartial):

@using Report.Helpers
@model Models.Reivindication
<link rel="Stylesheet" href="../../Content/Site.css" type="text/css" />
<div class="reivindicationEditorRow">
@using (Html.BeginCollectionItem("Reivindications"))
{
    <text>Reivindication code</text> @Html.TextBoxFor(m => m.Code, new { style="width:150px", data_containerPrefix=this.ViewData["ContainerPrefix"]}) 
    <text>Result</text> @Html.TextBoxFor(m => m.Outcome, new { style="width:150px" , data_containerPrefix=this.ViewData["ContainerPrefix"]}) 
    <a href="#" class="deleteRow">delete</a>  
}
</div>
<script>
    $("a.deleteRow").live("click", function () {
        $(this).parents("div.reivindicationEditorRow:first").remove();
        return false;
    });
</script>

我有这个助手类:

public static class HtmlPrefixScopeExtensions
    {
        private const string idsToReuseKey = "__htmlPrefixScopeExtensions_IdsToReuse_";

        public static IDisposable BeginCollectionItem(this HtmlHelper html, string collectionName)
        {
            if (html.ViewData["ContainerPrefix"] != null)
            {
                collectionName = string.Concat(html.ViewData["ContainerPrefix"], ".", collectionName);
            }

            var idsToReuse = GetIdsToReuse(html.ViewContext.HttpContext, collectionName);
            string itemIndex = idsToReuse.Count > 0 ? idsToReuse.Dequeue() : Guid.NewGuid().ToString();

            var htmlFieldPrefix = string.Format("{0}[{1}]", collectionName, itemIndex);
            html.ViewData["ContainerPrefix"] = htmlFieldPrefix;

            // 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, htmlFieldPrefix);
        }

        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;
            }
        }
    }

在我的家庭控制器中,我添加了这样的项目:

[HttpPost]
        [OutputCache(NoStore = true, Duration = 0, VaryByParam = "*")]
        public PartialViewResult AddStrike(string containerPrefix)
        {
            ViewData["ContainerPrefix"] = containerPrefix;
            return PartialView("_StrikePartial", new Strike());
        }
        [HttpPost]
        [OutputCache(NoStore = true, Duration = 0, VaryByParam = "*")]
        public PartialViewResult AddReivindication(string containerPrefix)
        {
            ViewData["ContainerPrefix"] = containerPrefix;
            return PartialView("_ReivindicationPartial", new Reivindication());
        }
        [HttpPost]
        [OutputCache(NoStore = true, Duration = 0, VaryByParam = "*")]
        public PartialViewResult AddStrikeDate(string containerPrefix)
        {
            ViewData["ContainerPrefix"] = containerPrefix;
            return PartialView("_StrikeDatePartial", new StrikeDate());
        }

如果我添加第一个打击并在打击内部我添加一个reivindication它呈现好。 如果我添加第二个Strike并且在第二个Strike中添加一个reivindication,该页面将在第一次攻击中呈现新的reivindication。但是,如果我单击“保存”,则MainViewModel是正确的。在调试Strike [1] .Reivindications [0]看起来是正确的。 只有渲染是错误的。 这是渲染页面:

div id="reivindicationsDiV" style="top: 10px;">
        Principais reivindicações expressas e resultados obtidos
            <a style="float: right;" href="/Report/Home/AddReivindication?containerPrefix=Strikes%5Bd3fc7e4a-0571-40cb-9b2d-b4383b22eae8%5D&amp;class=addReivindicationItem" data-ajax-update="#reivindicationsDiV" data-ajax-mode="after" data-ajax-method="POST" data-ajax="true">Adicionar Reivindicação...</a>
<link href="../../Content/Site.css" rel="Stylesheet" type="text/css">




<div class="reivindicationEditorRow">
<input name="Strikes[d3fc7e4a-0571-40cb-9b2d-b4383b22eae8].Reivindications.index" type="hidden" value="dd1716b2-a832-4f2a-8b99-f230b20df2b5" autocomplete="off">
    Reivindicação <input name="Strikes[d3fc7e4a-0571-40cb-9b2d-b4383b22eae8].Reivindications[dd1716b2-a832-4f2a-8b99-f230b20df2b5].Code" id="Strikes_d3fc7e4a-0571-40cb-9b2d-b4383b22eae8__Reivindications_dd1716b2-a832-4f2a-8b99-f230b20df2b5__Code" style="width: 150px;" type="text" value="11" data-val-number="The field Code must be a number." data-val="true" data-containerprefix="Strikes[d3fc7e4a-0571-40cb-9b2d-b4383b22eae8].Reivindications[dd1716b2-a832-4f2a-8b99-f230b20df2b5]">    Resultado <input name="Strikes[d3fc7e4a-0571-40cb-9b2d-b4383b22eae8].Reivindications[dd1716b2-a832-4f2a-8b99-f230b20df2b5].Outcome" id="Strikes_d3fc7e4a-0571-40cb-9b2d-b4383b22eae8__Reivindications_dd1716b2-a832-4f2a-8b99-f230b20df2b5__Outcome" style="width: 150px;" type="text" value="12" data-val-number="The field Outcome must be a number." data-val="true" data-containerprefix="Strikes[d3fc7e4a-0571-40cb-9b2d-b4383b22eae8].Reivindications[dd1716b2-a832-4f2a-8b99-f230b20df2b5]">    <a class="deleteRow" href="#">delete</a>  
</div>
        <link href="../../Content/Site.css" rel="Stylesheet" type="text/css">




<div class="reivindicationEditorRow">
<input name="Strikes[a3c19f26-f4ed-47c9-9870-d6b2d3bc0adc].Reivindications.index" type="hidden" value="4e3d2042-dce9-4143-af69-ab816a69297b" autocomplete="off">
    Reivindicação <input name="Strikes[a3c19f26-f4ed-47c9-9870-d6b2d3bc0adc].Reivindications[4e3d2042-dce9-4143-af69-ab816a69297b].Code" id="Strikes_a3c19f26-f4ed-47c9-9870-d6b2d3bc0adc__Reivindications_4e3d2042-dce9-4143-af69-ab816a69297b__Code" style="width: 150px;" type="text" value="" data-val-number="The field Code must be a number." data-val="true" data-containerprefix="Strikes[a3c19f26-f4ed-47c9-9870-d6b2d3bc0adc].Reivindications[4e3d2042-dce9-4143-af69-ab816a69297b]">    Resultado <input name="Strikes[a3c19f26-f4ed-47c9-9870-d6b2d3bc0adc].Reivindications[4e3d2042-dce9-4143-af69-ab816a69297b].Outcome" id="Strikes_a3c19f26-f4ed-47c9-9870-d6b2d3bc0adc__Reivindications_4e3d2042-dce9-4143-af69-ab816a69297b__Outcome" style="width: 150px;" type="text" value="" data-val-number="The field Outcome must be a number." data-val="true" data-containerprefix="Strikes[a3c19f26-f4ed-47c9-9870-d6b2d3bc0adc].Reivindications[4e3d2042-dce9-4143-af69-ab816a69297b]">    <a class="deleteRow" href="#">delete</a>  
</div>
</div>

Id似乎是正确的,但第二次重新指示应该在第二次攻击DatesDiV中呈现(此处未显示) 这让我发疯,欢迎任何帮助 Thanx提前

0 个答案:

没有答案