Html Helper从Model State获取值

时间:2011-10-12 04:11:48

标签: asp.net-mvc asp.net-mvc-3

Asp.Net MVC 3

我似乎有一个类似的问题,这篇文章由Darin Dimitrov回答。所以,Darin如果你正在读这篇文章,请帮忙:)。

asp.net-mvc2 - Strongly typed helpers not using Model?

我遇到的问题是我正在寻找一个包含模型状态中发布值的html帮助器。

例如,如果我使用这样的编辑器:

@Html.EditorFor(model => model.SelectedTags)

我可以看到发布的值。问题是我需要一种方法来获取此值而不创建文本框,我只想要字符串,因为我需要在一些JavaScript中。

我尝试过DisplayFor,但不包含已发布的值:

@Html.DisplayFor(model => model.SelectedTags)

顺便说一下,我发现这种行为并不直观。我花了几个小时从MVCContrib调试ModelStateToTempDataAttribute,认为这是他们的代码中导入/导出模型状态的错误。

感谢您的帮助!

编辑 - 添加了Repro代码

采取以下步骤重现:

  1. 启动项目。 Property1应为空(必填),Property2应为“abc”
  2. 将Property2更改为“xxx”
  3. 提交表单(通知ClientValidationEnabled为False)
  4. 表单已过帐,重定向,加载(PRG)。 Property2文本框有“xxx”,右下方你会看到DisplayFor的“abc”。
  5. 控制器

    [ModelStateToTempData] //From MVCContrib
    public class HomeController : Controller
    {
    
        [HttpGet]
        public ActionResult Index()
        {
            //simulate load from db
            var model = new FormModel() { MyProperty2 = "abc" }; 
    
            return View(model);
        }
    
        [HttpGet]
        public ActionResult Success()
        {
            return View();
        }
    
        [HttpPost]
        public ActionResult Index(FormModel model)
        {
            if (ModelState.IsValid)
            {
                return RedirectToAction("Success");
            }
            else
            {
                return RedirectToAction("Index");
            }
        }
    }
    

    模型

    public class FormModel
    {
      [Required]
      public string MyProperty1 { get; set; }
    
      public string MyProperty2 { get; set; }
    }
    

    查看

    @model MvcApplication4.Models.FormModel
    @using (Html.BeginForm()) {
    @Html.ValidationSummary(true)
    <fieldset>
        <legend>FormModel</legend>
    
        <div class="editor-label">
            @Html.LabelFor(model => model.MyProperty1)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.MyProperty1)
            @Html.ValidationMessageFor(model => model.MyProperty1)
        </div>
    
        <div class="editor-label">
            @Html.LabelFor(model => model.MyProperty2)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.MyProperty2)
            @Html.ValidationMessageFor(model => model.MyProperty2)
        </div>
    
        @Html.DisplayFor(model => model.MyProperty2)
    
        <p>
            <input type="submit" value="Save" />
        </p>
    </fieldset>
    }
    

    配置:

    <add key="ClientValidationEnabled" value="false" />
    

    ModelStateToTempData(MVCContrib):

    public class ModelStateToTempDataAttribute : ActionFilterAttribute
        {
            public const string TempDataKey = "__MvcContrib_ValidationFailures__";
    
            /// <summary>
            /// When a RedirectToRouteResult is returned from an action, anything in the ViewData.ModelState dictionary will be copied into TempData.
            /// When a ViewResultBase is returned from an action, any ModelState entries that were previously copied to TempData will be copied back to the ModelState dictionary.
            /// </summary>
            /// <param name="filterContext"></param>
            public override void OnActionExecuted(ActionExecutedContext filterContext)
            {
                var modelState = filterContext.Controller.ViewData.ModelState;
    
                var controller = filterContext.Controller;
    
                if(filterContext.Result is ViewResultBase)
                {
                    //If there are failures in tempdata, copy them to the modelstate
                    CopyTempDataToModelState(controller.ViewData.ModelState, controller.TempData);
                    return;
                }
    
                //If we're redirecting and there are errors, put them in tempdata instead (so they can later be copied back to modelstate)
                if((filterContext.Result is RedirectToRouteResult || filterContext.Result is RedirectResult) && !modelState.IsValid)
                {
                    CopyModelStateToTempData(controller.ViewData.ModelState, controller.TempData);
                }
            }
    
            private void CopyTempDataToModelState(ModelStateDictionary modelState, TempDataDictionary tempData)
            {
                if(!tempData.ContainsKey(TempDataKey)) return;
    
                var fromTempData = tempData[TempDataKey] as ModelStateDictionary;
                if(fromTempData == null) return;
    
                foreach(var pair in fromTempData)
                {
                    if (modelState.ContainsKey(pair.Key))
                    {
                        modelState[pair.Key].Value = pair.Value.Value;
    
                        foreach(var error in pair.Value.Errors)
                        {
                            modelState[pair.Key].Errors.Add(error);
                        }
                    }
                    else
                    {
                        modelState.Add(pair.Key, pair.Value);
                    }
                }
            }
    
            private static void CopyModelStateToTempData(ModelStateDictionary modelState, TempDataDictionary tempData)
            {
                tempData[TempDataKey] = modelState;
            }
        }
    

2 个答案:

答案 0 :(得分:3)

你可以从像

这样的modelstate字典中读取这些值
<%:Html.ViewData.ModelState["key"] %>

但是,在我看来,SelectedTags是在调用EditorFor(model=>model.SelectedTags)时显示以进行编辑的对象的枚举。在这种情况下,通过调用Html.ViewData.ModelState["SelectedTags"]来获取任何内容的可能性极小。您将不得不迭代ModelState字典中的键,并检查键是否以SelectedTags前缀开头,然后您可以按顺序读取其值。

答案 1 :(得分:1)

在您的观看次数中 - &gt;共享 - &gt; DisplayTemplates,创建SelectedTags.cshtml

这将是您的显示模板。在里面写点什么

@model YourProject.WebUI.Models.SelectedTags

@for(int i = 0; i < Model.Tags.Count(); i++){
   // Assuming that selected tags contains a list of tags.
   // Replace <p> with whatever feels suitable
   <p>Model.Tags[i]</p>
}

然后,您可以在视图中使用此显示模板:

@Html.DisplayFor(model => model.SelectedTags,"SelectedTags") 

这也应该有效:

@Html.DisplayFor(model => model.SelectedTags)