在MVC中处理动态HTML类的优雅方法

时间:2016-12-13 03:22:39

标签: c# asp.net-mvc html-helper

我有一个自定义的MVC HTML Helper方法,如下所示:

public static MvcHtmlString Div (this HtmlHelper htmlHelper,
VehicleStatusViewModel vehicleStatus, string classType)

我调用这个帮助器方法来帮助我在我的视图中选择用于div的正确引导类。在方法内部,我使用一个开关来遍历vehicleStatus的可能状态并分配相应的bootstrap类。 I.E.面板 - 如果vehicleStatus = 1则成功或面板 - 如果vehicleStatus = 2则面临危险。

但是,我可能想要根据VehicleStatus的某个返回状态再次指定一个特定的glyphicon。将来,我可能会有更多的类类型。

在我看来,当我调用这个Helper方法时,我想传递一个classType(即panel或glyphicon)。在我的Helper方法中,无需为每个可能的类类型复制我的开关代码,我想要一个优雅的解决方案来呈现特定的classType我的视图正在请求并返回一个具有适当分配的TagBuilder div class / class-type,这样:

@Html.Div(vehicleStatus, "panel")
// Would resolve and return, if vehicleStatus was 1: 
<div class="panel panel-success"> </div>

// Calling the same method, vehicleStatus = 1 but expecting a respective
// glyphicon:
@Html.Div(vehicleStatus, "glyphicon")
<div class="glyphicon glyphicon-remove-circle"> </div>

1 个答案:

答案 0 :(得分:1)

嗯,您对问题的描述听起来像是基类或接口设置的完美示例(通过覆盖基类的行为和/或以不同方式实现接口,将来添加其他类类型的可能性) 。

这可能是也可能不是你想要的。我之前使用过类似的模式,通常是在域中,但有时用于Razor目的。在这种情况下,可以使用基类。完成后,我意识到我略微过度设计了这个例子。你可能很容易逃脱2级,直到你达到你想要的更多点。

public abstract class HtmlTag
{
    private readonly String _tag;

    //allow different type of tags to be rendered
    protected HtmlTag(String tag)
    {
        if (String.IsNullOrWhiteSpace(tag)) 
            throw new ArgumentException("Value cannot be null or whitespace.", "tag");
        _tag = tag;
    }
    //require a VehicleStatus for rendering to an HtmlString
    public String ToHtmlString( VehicleStatus vehicleStatus )
    {
        var tag = new TagBuilder( _tag );
        this.CreateTag( tag, vehicleStatus );
        return tag.ToString();
    }
    //require subclasses to implement the CreateTag method
    //this method will allow subclasses to modify the tag builder as needed
    //depending on the vehicle status
    protected abstract void CreateTag( TagBuilder tagBuilder, VehicleStatus vehicleStatus );
}

然后,如果您特别想要divspan,例如:

public abstract class Div : HtmlTag
{
    protected Div( )
        : base( "div" )
    {
    }
}
public abstract class Span : HtmlTag
{
    protected Span()
        : base("span")
    {
    }
}

最后,您需要做的就是创建实现CreateTag方法的类:

public class PanelDiv : Div
{
    protected override void CreateTag( TagBuilder tagBuilder, VehicleStatus vehicleStatus )
    {
        tagBuilder.AddCssClass( "panel" );
        tagBuilder.AddCssClass(vehicleStatus == VehicleStatus.Success 
            ? "panel-success" 
            : "panel-danger");
    }
}
public class GlyphiconDiv : Div
{
    protected override void CreateTag( TagBuilder tagBuilder, VehicleStatus vehicleStatus )
    {
        tagBuilder.AddCssClass( "glyphicon" );
        tagBuilder.AddCssClass( vehicleStatus == VehicleStatus.Success 
            ? "glyphicon-remove-circle" 
            : "glyphicon-add-circle" );
    }
}

如果您想添加其他类型,您需要做的只是:

public class MyOtherDiv : Div
{
    protected override void CreateTag( TagBuilder tagBuilder, VehicleStatus vehicleStatus )
    {
        //adjust the tag here based on vehicle status
    }
}

最后,你的HtmlHelper:

public static class DivHtmlHelperExtensions
{
    public static IHtmlString Div( this HtmlHelper htmlHelper, VehicleStatus vehicleStatus, HtmlTag htmlTag )
    {
        //simply return the HtmlString representation of your HtmlTag you passed in
        return new HtmlString( htmlTag.ToHtmlString( vehicleStatus ) );
    }
    //call this method likeso (from a view):
    //@Html.Div(vehicleStatus, new PanelDiv());
    //@Html.Div(vehicleStatus, new GlyphiconDiv());
}

如果你发现自己一遍又一遍地做同样的事情,你可以稍微重构一下父类来处理更多的责任:

public abstract class Div : HtmlTag
{
    private readonly String _className;
    private readonly String _trueCssClass;
    private readonly String _falseCssClass;

    protected Div( String className, String trueCssClass, String falseCssClass )
        : base( "div" )
    {
        _className = className;
        _trueCssClass = trueCssClass;
        _falseCssClass = falseCssClass;
    }
    //the div will use the constructing parameters to populate the classes instead
    protected override void CreateTag( TagBuilder tagBuilder, VehicleStatus vehicleStatus )
    {
        tagBuilder.AddCssClass( _className );
        tagBuilder.AddCssClass( vehicleStatus == VehicleStatus.Success 
            ? _trueCssClass 
            : _falseCssClass );
    }
}
//and your subclass:
public class PanelDiv : Div
{
    public PanelDiv()
        : base( "panel", "panel-success", "panel-danger" )
    {
    }
}

如果这不是你想要的,请告诉我。