【问题标题】:DRY in the MVC ViewMVC 视图中的 DRY
【发布时间】:2009-10-24 11:57:30
【问题描述】:

我一直在使用 asp.net 网络表单,有人认为我喜欢的是与生成的标记的一致性,例如如果您为 TextField 创建复合控件,则可以在单个类中控制生成的标记,并且不会破坏 SRP:

<form:textfield id="firstName" runat="server" required="true" label="First Name" />

如果你打算手动生成标记,它可能看起来像这样:

<label for="firstName" id="lbl_firstName">Name <span class="required">*</span></label>
<input id="firstName" name="firstName" type="text" value="" />

问题是何时想要更改某些内容,例如添加包装 div 或移动跨度。在最坏的情况下,您必须编辑数千个视图。

这就是我真正喜欢 MVC Contrib FluentHtml 的原因。

<%= this.TextBox(x => x.Message.PostedBy).Class("required").Label("Name") %>

我的问题是,您认为为上面的代码行添加包装 div 的最佳方式是什么?由于上述论点,我认为手写不是一种选择?也许扩展 TextBox : MvcContrib.FluentHtml.Elements.TextInput?

【问题讨论】:

    标签: asp.net-mvc mvccontrib


    【解决方案1】:

    你检查过 MvcContrib 项目中的 InputBuilder 吗?它也用于 Codecampserver。看看,我想你会喜欢的。

    【讨论】:

    【解决方案2】:

    老实说,我认为您给出的示例不适用于现实世界。文本框是文本框。如果你需要一个,你渲染一个。
    如果您需要一个更“复杂”的控件,例如包装在 div 标记中的文本框,那么您可以有一个部分视图。

    例如,型号:

    public class CustomControlModel {
        public string Name { get; set; }
        public string Value { get; set; }
        public string Class { get; set; }
        public bool WrapInDivTag { get; set; }
        //you get the idea
    }
    

    自定义控件:

    <%@ Control Inherits="System.Web.Mvc.ViewUserControl<CustomControlModel>" %>
    <%if (Model.WrapInDivTag) {%> <div> <% } %>
        <%=Html.TextBox(Model.Name, Model.Value, new { @class = Model.Class })%>
    <%if (Model.WrapInDivTag) {%> </div> <% } %>
    

    渲染时:

    <%Html.RenderPartial("CustomControl", 
        new CustomControlModel { Name = "name", WrapInDivTag = true }); %>
    

    这是一个非常简单的例子,但我希望它能解释我为什么建议部分视图。不要忘记您可以公开另一个属性来获取要渲染的标签等。

    【讨论】:

    • 其实我不同意你的观点,这个例子很简单,但它仍然有效。 Fluent TextBox 也呈现标签是有原因的,因此您不必手动编写 i 。出于完全相同的原因,您可能希望添加一个包装 div 并控制单个位置的输出。
    • @orjan,如果该方法TextBox 呈现&lt;intput type="text" /&gt; &lt;label /&gt; 标签,那是因为它们彼此相关。但是如果你想渲染一个输入,标签一个div标签,那么我不得不认为它不再是一个简单的文本框,而是一个自定义控件。
    • @çağdaş,我同意输入和标签彼此相关,但它们也“需要”某种包装元素
    • 来跨浏览器CSS 样式,这就是复合控件很棒的原因。为每个输入字段创建局部视图对我来说听起来像是很大的开销,而且代码看起来也不整洁。

  • 其实你不需要为每个输入创建一个局部视图。部分视图也可以有模型。我将编辑答案以举个例子......
  • 我同意 orjan,orjan 给出的代码示例简洁且可重用。部分视图适用于较大的组件。
  • 【解决方案3】:

    InputBuilders 是一种选择。使用 FluentHtml,您可以创建自定义元素,如下所示:

    public class TextBoxInContainer : TextInput<TextBox>
    {
        public TextBoxInContainer (string name) : base(HtmlInputType.Text, name) { }
    
        public TextBoxInContainer (string name, MemberExpression forMember, IEnumerable<IBehaviorMarker> behaviors) : base(HtmlInputType.Text, name, forMember, behaviors) { }
    
        protected override ToString()
        {
             divBuilder = new TagBuilder(HtmlTag.Div);
             divBuilder.InnerHtml = ToString();
             return divBuilder.ToString(TagRenderMode.SelfClosing);
        }
    }
    

    要从您的视图中使用它,您可以像这样扩展 IViewModelContainer:

    public static MyTextBox TextBoxInContainer <T>(this IViewModelContainer<T> view, Expression<Func<T, object>> expression) where T : class
    {
        return new TextBoxInContainer (expression.GetNameFor(view), expression.GetMemberExpression(), view.Behaviors)
            .Value(expression.GetValueFrom(view.ViewModel));
    }
    

    然后,如果您想将容器更改为站点范围内的跨度,请更改 TextBoxInContainer 的 ToString 方法。

    【讨论】:

    • 2 年后这是使用 FluentHtml 的首选方式吗?
    猜你喜欢
    相关资源
    最近更新 更多
    热门标签