2013-08-07 14 views
12

Tek bir görünümde birden çok formla bazı sorunlara yol açıyor. Bütün BankInfos her biri için ayrı formlar içinde birbirinden altında görüntülenmesini istediğiniz, benim ViewModelMVC görünümünde birden çok form: ModelState tüm formlara uygulanır

public class ChangeBankAccountViewModel 
{ 
    public IEnumerable<BankInfo> BankInfos { get; set; } 
} 

public class BankInfo 
{ 
    [Required] 
    public string BankAccount { get; set; } 
    public long Id { get; set; } 
} 

:

Aşağıdaki ViewModel olduğunu varsayalım.

@model BankInfo 

@using (Html.BeginForm()) 
{ 
    @Html.HiddenFor(m => m.InvoiceStructureId) 
    @Html.TextBoxFor(m => m.IBANAccount) 

    <button type="submit">Update this stuff</button> 
} 

yanı sıra benim gerçek görünüm BankInfo:

Bunu başarmak için, ben kısmi görünümü _EditBankInfo kullanıyorum

foreach(var info in Model.BankInfos) 
{ 
    Html.RenderPartial("_EditBankInfo", info); 
} 

Son, burada benim 2 Aksiyon Yöntemleri şunlardır:

[HttpGet] 
public ActionResult BankInfo() 
{ 
    return View(new ChangeBankAccountViewModel{BankInfos = new [] {new BankInfo...}); 
} 
[HttpPost] 
public ActionResult BankInfo(BankInfo model) 
{ 
    if(ModelState.IsValid) 
     ModelState.Clear(); 
    return BankInfo(); 
} 

Tüm bunlar hunky dory üzerinde çalışıyor: Doğrulama düzgün çalışıyor, yayınlanan model tanınıyor ve onaylanıyor doğru ... Ancak, sayfa yeniden yüklendiğinde sorun ortaya çıktığında. Aynı formu birden çok kez kullanıyorum, ModelState'im birden çok kez uygulanacak. Dolayısıyla, bir formda bir güncelleme gerçekleştirilirken, bir sonraki sayfadaki yüklenen değerler gönderilecektir.

Bunun olmasını önlemek için herhangi bir yolu var mı?

Kısmi görünümler olmadan bunu yapmayı denedim, ancak bu adlandırma biraz vidalıyor (benzersizdir, ancak sunucuya dayalı model oluşturma işlemi bunları tanımayacaktır).

Herhangi bir cevap için teşekkürler.

+0

Formun teslim edildiği denetleyici eylemini gösterir misiniz? Özellikle parametre olarak aldığı model ve manzaraya geçtiği model ile ilgileniyorum. –

+0

@DarinDimitrov, Eklendi. Bunun basitleştirilmiş bir örnek olduğunu biliyorsunuz, ancak temel kurulum orada olmalı. Ayrıca, muhtemelen bir çeşit PRG senaryosunu kullanıyorum. – Kippie

cevap

10

Bu biraz zor. İşte nasıl çözülebilir. _EditBankInfo.cshtml parçasını, bu gibi görünen bir editör şablonuna (~/Views/Shared/EditorTemplates/BankInfo.cshtml) taşıyarak başlayın (şablonun adının ve konumunun önemli olduğuna dikkat edin. ~/Views/Shared/EditorTemplates içine yerleştirilmeli ve IEnumerable<T> koleksiyon özelliğinizde kullanılan yazılan adın adıyla adlandırılmalıdır.

@model BankInfo 

<div> 
    @using (Html.BeginForm()) 
    { 
     <input type="hidden" name="model.prefix" value="@ViewData.TemplateInfo.HtmlFieldPrefix" /> 
     @Html.HiddenFor(m => m.Id) 
     @Html.TextBoxFor(m => m.BankAccount) 

     <button type="submit">Update this stuff</button> 
    } 
</div> 

ve ardından ana görünümde foreach döngü kurtulmak ve EditorFor yardımcı için basit bir çağrı ile değiştirin: Şimdi

@model ChangeBankAccountViewModel 

@Html.EditorFor(x => x.BankInfos) 

sizin durumunuzda BankInfo.cshtml) 'dir BankInfos koleksiyonunun her elemanı için özel editör şablonu oluşturulacaktır. Ve kısmi aksine, editör şablon seyir bağlamını saygı ve şu işaretlemeyi üretecektir: Her alan formu gönderirken artık hiçbir çakışma olacak belirli bir isme sahip beri Şimdi

<div> 
    <form action="/" method="post">  
     <input type="hidden" name="model.prefix" value="BankInfos[0]" /> 
     <input data-val="true" data-val-number="The field Id must be a number." data-val-required="The Id field is required." id="BankInfos_0__Id" name="BankInfos[0].Id" type="hidden" value="1" /> 
     <input data-val="true" data-val-required="The BankAccount field is required." id="BankInfos_0__BankAccount" name="BankInfos[0].BankAccount" type="text" value="account 1" />  
     <button type="submit">Update this stuff</button> 
    </form> 
</div> 

<div> 
    <form action="/" method="post">  
     <input type="hidden" name="model.prefix" value="BankInfos[1]" /> 
     <input data-val="true" data-val-number="The field Id must be a number." data-val-required="The Id field is required." id="BankInfos_1__Id" name="BankInfos[1].Id" type="hidden" value="2" /> 
     <input data-val="true" data-val-required="The BankAccount field is required." id="BankInfos_1__BankAccount" name="BankInfos[1].BankAccount" type="text" value="account 2" />  
     <button type="submit">Update this stuff</button> 
    </form> 
</div> 

... 

. Her bir formun içine açıkça yerleştirdiğim model.prefix adlı gizli alana dikkat edin.Bu BankInfo türü için özel bir modeli ciltteki tarafından kullanılacaktır: senin Application_Start tescil edilecektir

public class BankInfoModelBinder: DefaultModelBinder 
{ 
    public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) 
    { 
     bindingContext.ModelName = controllerContext.HttpContext.Request.Form["model.prefix"]; 
     return base.BindModel(controllerContext, bindingContext); 
    } 
} 

:

ModelBinders.Binders.Add(typeof(BankInfo), new BankInfoModelBinder()); 

Tamam, şimdi biz gitmek için iyidir. ModelState.Clear denetleyicinizin eylemine artık gerek duymadığınızdan kurtulun:

[HttpGet] 
public ActionResult BankInfo() 
{ 
    var model = new ChangeBankAccountViewModel 
    { 
     // This is probably populated from some data store 
     BankInfos = new [] { new BankInfo... }, 
    } 
    return View(model); 
} 

[HttpPost] 
public ActionResult BankInfo(BankInfo model) 
{ 
    if(ModelState.IsValid) 
    { 
     // TODO: the model is valid => update its value into your data store 
     // DO NOT CALL ModelState.Clear anymore. 
    } 

    return BankInfo(); 
} 
+0

Teşekkürler, Darin. Bana birkaç hile öğreten müthiş bir örnek (EditorFor'un Sayısız koleksiyona izin verdiğini kim biliyordu?). Ben sadece bir model hatası için bir model hatası eklemek gerekir durumunda önek bulmakta küçük bir sorun var, ama eminim ki bir tane anlayacağım. – Kippie

İlgili konular