【问题标题】:How do I create an editor template that works with existing data?如何创建适用于现有数据的编辑器模板?
【发布时间】:2015-06-17 20:04:13
【问题描述】:

我创建了一个编辑器模板来显示表单中包含的文本框。

    @model WebApplication1.Models.PersonViewModel

<input type="text" class="form-control" name="@ViewData.TemplateInfo.HtmlFieldPrefix" value=""/>

我只是想在用于收集此模型数据的所有输入文本框中包含“表单控件”类。

public class PersonViewModel
{ 
    [UIHint("_TextFormControl")]
    public string FirstName { get; set; }
    [UIHint("_TextFormControl")]
    public string LastName { get; set; }
    public int Age { get; set; }

}  

当表单开始为空白时,这很有效,但是,当我将模板用于预先填充了数据的表单时,例如当我想编辑现有模型时,我收到错误消息:“模型项传入该字典的类型为“System.String”,但该字典需要一个“WebApplication1.Models.PersonViewModel”类型的模型项。”

这是我的控制器:

 // GET: /Person/Edit/5
    [HttpGet]
    public ActionResult Edit(int? id)
    {
        if (id == null)
        {
            return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
        }

        Person person = db.Persons.Find(id);

        if (person == null)
        {
            return HttpNotFound();
        }

        return View(person);
    }

如何允许此编辑器用于现有数据以及新表单?

【问题讨论】:

    标签: c# asp.net asp.net-mvc forms razor


    【解决方案1】:

    您已经为 typeof PersonViewModel 创建了一个 EditorTemplate,但您使用 [UIHint("_TextFormControl")] 应用于 typeof string 意味着您将 string 传递给模板,而不是 PersonViewModel。目前尚不清楚您在此处尝试实现的目标,但根据您当前的模型,模板需要是

    @model String
    @Html.TextBox("") // or @Html.TextBoxFor(m => m)
    

    但这与在视图中使用@Html.EditorFor(m =&gt; m.FirstName)(或TextBoxFor())相同。您可能会这样做的一个原因是生成多个 html 元素,例如

    @model String
    @Html.Label("")
    @Html.TextBox("")
    @Html.ValidationMessage("")
    

    这样在主视图中使用@Html.EditorFor(m =&gt; m.FirstName) 会为验证消息生成标签、文本框和占位符。

    但是,使用自定义编辑器模板的真正好处之一是当您将它们用于复杂类型并希望这些类型具有一致的 UI 时。例如,您可以为 typeof PersonViewModel 创建一个模板。在/Views/Shared/EditorTemplates/PersonViewModel.cshtml中(注意模板名称必须与类型名称匹配)

    @model WebApplication1.Models.PersonViewModel
    <div>
      @Html.LabelFor(m => m.FirstName)
      @Html.TextBoxFor(m => m.FirstName)
      @Html.ValidationMessageFor(m => m.FirstName)
    </div>
    <div>
      @Html.LabelFor(m => m.LastName)
      @Html.TextBoxFor(m => m.LastName)
      @Html.ValidationMessageFor(m => m.LastName)
    </div>
    .... // ditto for other properties of PersonViewModel
    

    然后在主视图中

    @model WebApplication1.Models.PersonViewModel
    @Html.EditorFor(m => m)
    

    这也适用于PersonViewModel 的集合,并为集合中的每个PersonViewModel 生成一个编辑器模板

    @model IEnumerable<WebApplication1.Models.PersonViewModel>
    @Html.EditorFor(m => m)
    

    同样,如果您有另一个模型包含属性public PersonViewModel Person { get; set; },您可以使用@Html.EditorFor(m =&gt; m.Person)

    旁注:

    1. 您声称​​“当表单开始为空白时效果很好” 意味着您没有将 PersonViewModel 的新实例传递给您的 在“创建”方法中查看是不好的做法。你的控制器 方法应该将一个实例传递给视图。
    2. 您当前在其中手动构建输入元素的模板 不会起作用,因为您从未设置过 value 属性。在 此外,您不添加用于客户端的 data-val-* 属性 侧面验证。始终使用强类型的 html 助手 生成您的 html,以便您获得正确的 2-way 模型绑定并采取 充分利用 MVC 的所有内置功能。

    【讨论】:

    • 这非常有帮助。谢谢你。我的目标是将“表单控制”类(引导程序工作)应用于所有输入框。我的想法是,我不会为每个输入框使用 @Html.EditorFor(model => model.Name, new{@class= 'form-control'}) ,而是使用模板。这种模板的应用有意义吗?无论如何,显然有很多重构工作摆在我面前。
    • 好吧,你可以这样做——在第一个 sn-p 中,它会是 @model String @Html.TextBoxFor(m =&gt; m, new { @class = "form-control" }),但这会非常不灵活——每个 string 属性都将呈现为具有该类的文本框,但是修改任何东西都没有灵活性(例如添加另一个类名)。
    • 更好的选择是创建一个 html 辅助扩展方法 - 比如BootStrapTextBoxFor() 生成 html。 This answer 给出了一个可能的示例(在这种情况下,它会生成标签、文本框和验证消息,但您可以为每个元素创建单独的辅助方法)。使用扩展方法的一个优点是您可以添加其他重载,并且可以将它们编译到单独的 .dll 中以供跨多个项目使用。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-08-07
    • 1970-01-01
    • 1970-01-01
    • 2014-03-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多