2011-06-07 62 views
4

我創建了一個可變長度列表的視圖,如下所述:http://blog.stevensanderson.com/2010/01/28/editing-a-variable-length-list-aspnet-mvc-2-style/MVC 3.0編輯可變長度列表並使用PRG模式

我正在嘗試使用帶有動作過濾器的PRG模式,如第13點所述:http://weblogs.asp.net/rashid/archive/2009/04/01/asp-net-mvc-best-practices-part-1.aspx

我有一個編輯動作:

[HttpGet, ImportModelStateFromTempData] 
    public ActionResult Edit(int id) 
    { 
    } 

和後動作:

[HttpPost, ExportModelStateToTempData] 
    public ActionResult Edit(int id, FormCollection formCollection) 
    { 
     if (!TryUpdateModel<CategoryEntity>(category, formCollection)) 
     { 
      return RedirectToAction("Edit", new { id = id }); 
     } 

     // succes, no problem processing this... 
     return RedirectToAction("Edit", new { id = id }); 
    } 

一切工作正常,包括驗證和錯誤消息。

我唯一的問題是新增項目和刪除項目(客戶端刪除/添加)在重定向後不會保留。我試圖找到一種方式來更新我的模型後重新導入新項目。我將ImportModelStateFromTempData屬性更改爲使用OnActionExecuting覆蓋而不是OnActionExecuted覆蓋,以便在操作中使用ModelState,但我沒有看到從傳入的ModelState中更新模型的乾淨方法。

更改ImportModelStateFromTempData:

public class ImportModelStateFromTempData : ModelStateTempDataTransfer 
{ 
    public override void OnActionExecuting(ActionExecutingContext filterContext) 
    { 
     ModelStateDictionary modelState = filterContext.Controller.TempData[Key] as ModelStateDictionary; 

     if (modelState != null) 
     { 
      filterContext.Controller.ViewData.ModelState.Merge(modelState); 
     } 
     base.OnActionExecuting(filterContext); 
    } 

    public override void OnActionExecuted(ActionExecutedContext filterContext) 
    { 
     //ModelStateDictionary modelState = filterContext.Controller.TempData[Key] as ModelStateDictionary; 

     //if (modelState != null) 
     //{ 
     // //Only Import if we are viewing 
     // if (filterContext.Result is ViewResult) 
     // { 
     //  filterContext.Controller.ViewData.ModelState.Merge(modelState); 
     // } 
     // else 
     // { 
     //  //Otherwise remove it. 
     //  filterContext.Controller.TempData.Remove(Key); 
     // } 
     //} 
     base.OnActionExecuted(filterContext); 
    } 
} 

在此的任何輸入是非常讚賞,謝謝。

Harmen

更新:想我可能會添加一些更多的我的(僞)代碼,以使其更清晰:

public class CategoryEntity 
{ 
    public int Id; 
    public string Name; 
    public IEnumerable<CategoryLocEntity> Localized; 
} 

public class CategoryLocEntity 
{ 
    public int CategoryId; 
    public int LanguageId; 
    public string LanguageName; 
    public string Name; 
} 

我編輯觀點:對於

@model CategoryEntity 

@{ 
    ViewBag.Title = Views.Category.Edit; 
} 

<h2>@Views.Category.Edit</h2> 

<script src="@Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script> 
<script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script> 
<script type="text/javascript"><!-- 

    $(document).ready(function() { 
     $('#addItem').click(function() { 
      var languageId = $('#languageId').val(); 
      var index = $('#editor-rows').children().size() - 1; 
      $.ajax({ 
       url: this.href + '?languageId=' + languageId + '&index=' + index, 
       cache: false, 
       error: function (xhr, status, error) { 
        alert(error); 
       }, 
       success: function (html) { 
        $('#editor-rows').append(html); 
       } 
      }); 
      return false; 
     }); 

     $("a.removeItem").live("click", function() { 
      $(this).parents("div.editor-row:first").remove(); 
      return false; 
     }); 
    }); 

--></script> 

@using (Html.BeginForm()) 
{ 
    @Html.ValidationSummary(false) 
    <fieldset> 
     <legend>@Views.Shared.Category</legend> 
     @Html.HiddenFor(model => model.Id) 
     <div id="editor-rows"> 
      <div class="editor-row"> 
       <div class="editor-label"> 
        @Html.LabelFor(model => model.Name, Views.Shared.NameEnglish) 
       </div> 
       <div class="editor-field"> 
        @Html.EditorFor(model => model.Name) 
        @Html.ValidationMessageFor(model => model.Name) 
       </div> 
      </div> 

      @for (int i = 0; i < Model.Localized.Count; i++) 
      { 
       @Html.EditorFor(m => m.Localized[i], "_CategoryLoc", null, null) 
      } 
     </div> 

     <div class="editor-label"></div> 
     <div class="editor-field"> 
      @Html.DropDownList("languageId", (IEnumerable<SelectListItem>)ViewBag.LanguageSelectList) 
      @Html.ActionLink(Views.Category.AddNewLanguage, "AddNewLanguage", null, new { id = "addItem" }) 
     </div> 

     <p class="clear"> 
      <input type="submit" value="@Views.Shared.Save" /> 
     </p> 
    </fieldset> 
} 

<div> 
    @Html.ActionLink(Views.Shared.BackToList, "Index") 
</div> 

編輯模板CategoryLocEntity:

@model CategoryLocEntity 

<div class="editor-row"> 
    @Html.HiddenFor(model => model.Id) 
    @Html.HiddenFor(model => model.LanguageId) 
    <div class="editor-label"> 
     @Html.LabelFor(model => model.LanguageName, Model.LanguageName) 
    </div> 
    <div class="editor-field"> 
     @Html.EditorFor(model => model.Name) 
     <a href="#" class="removeItem">@Views.Shared.Remove</a> 
     @Html.ValidationMessageFor(model => model.Name) 
    </div> 
</div> 
+0

您好,感謝的解決方案,但是它不工作,我的情況,因爲我的收藏指數是不連續的(我使用額外的.index字段來這樣做)。 – hazzik 2012-10-06 21:24:17

回答

1

我找到了一個解決方案(可能不是最優雅的一個,但它適用於我)。我創建了自己的ModelStateValueProvider以與UpdateModel一起使用。該代碼基於DictionaryValueProvider。見http://www.java2s.com/Open-Source/CSharp/2.6.4-mono-.net-core/System.Web/System/Web/Mvc/DictionaryValueProvider%601.cs.htm

public class ModelStateValueProvider : IValueProvider 
{ 
    HashSet<string> prefixes = new HashSet<string>(StringComparer.OrdinalIgnoreCase); 
    ModelStateDictionary modelStateDictionary; 

    public ModelStateValueProvider(ModelStateDictionary modelStateDictionary) 
    { 
     if (modelStateDictionary == null) 
      throw new ArgumentNullException("modelStateDictionary"); 

     this.modelStateDictionary = modelStateDictionary; 

     FindPrefixes(); 
    } 

    private void FindPrefixes() 
    { 
     if (modelStateDictionary.Count > 0) 
      prefixes.Add(string.Empty); 

     foreach (var modelState in modelStateDictionary) 
      prefixes.UnionWith(GetPrefixes(modelState.Key)); 
    } 

    public bool ContainsPrefix(string prefix) 
    { 
     if (prefix == null) 
     { 
      throw new ArgumentNullException("prefix"); 
     } 

     return prefixes.Contains(prefix); 
    } 

    public ValueProviderResult GetValue(string key) 
    { 
     if (key == null) 
      throw new ArgumentNullException("key"); 

     return modelStateDictionary.ContainsKey(key) ? modelStateDictionary[key].Value : null; 
    } 

    static IEnumerable<string> GetPrefixes(string key) 
    { 
     yield return key; 
     for (int i = key.Length - 1; i >= 0; i--) 
     { 
      switch (key[i]) 
      { 
       case '.': 
       case '[': 
        yield return key.Substring(0, i); 
        break; 
      } 
     } 
    } 
} 

public class ModelStateValueProviderFactory : ValueProviderFactory 
{ 
    public override IValueProvider GetValueProvider(ControllerContext controllerContext) 
    { 
     return new ModelStateValueProvider(controllerContext.Controller.ViewData.ModelState); 
    } 
} 

我用它去編輯(獲取)動作,如:

[HttpGet, ImportModelStateFromTempData] 
public ActionResult Edit(int id) 
{ 
    var category = new CategoryEntity(id); 
    if (!ModelState.IsValid) 
    {  
    TryUpdateModel<CategoryEntity>(category, 
     new ModelStateValueProviderFactory().GetValueProvider(ControllerContext)); 
    } 
    return View(category); 
} 

期待着您的意見...