以编程方式确定在页面上输出什么类型的html元素 - 这个逻辑应该存在于何处?

时间:2012-04-25 21:08:23

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

我有一个下拉列表,表示与文档相关的各种“属性”字段。例如,文档可能有一个标签字段,这需要一个文本框来输入您的标签。或者它可能有一个位置字段,并且可以预先填充用户可以选择的各种位置类型的下拉列表。或者它可能是截止日期字段,我们有一个自定义日期选择器,用于选择日期。

我的问题:我想在我的控制器动作中声明一个HtmlHelper,它会在选择适当的属性字段时触发。我将切换到Attribute.Type是什么,并根据类型,我将在我的视图模型中返回适当的html在视图中呈现。如果我这样做,我可以单独测试我的switch语句。

我正在阅读声明控制器中的HtmlHelper是一个坏主意。我能理解这种情绪 - 有没有更好的方法可以做到这一点?我希望尽可能避免在我的视图中使用逻辑,因为我根本无法进行单元测试。

我看到的另一种方法是在视图模型中传递Attribute.Type,并在视图上执行切换逻辑以确定要调用的HtmlHelper方法。这是要走的路吗?提前谢谢。

编辑:我在谈论想要在代码隐藏中做这样的事情。我的单元测试将对viewModel.FieldHtml断言。我听到的是我应该将它放在另一个类中并让控制器调用它。但这就是它在控制器中的样子。它只是伪代码所以它并不完美,但它是为我所要求的内容提供背景。

public ActionResult GetValueInput(Guid attributeFieldUid)
{
    //you have to pass some stuff into the constructor but essentially this
    HtmlHelper html = new HtmlHelper();
    AttributeField field = GetAttributeFieldFromDb(attributeFieldUid);

    AttributeViewModel viewModel = new AttributeViewModel();
    switch(field.type)
    {
        case Dropdown:
            viewModel.FieldHtml = html.DropDownList();
            break;
        case Text:
            viewModel.FieldHtml = html.TextBox();
            break;
        case Date:
            // our own extension method
            viewModel.FieldHtml = html.OurDatePicker();
            break;
    }
}

我最初看到的另一个选项是在剃刀视图上基本上执行此switch语句。但我认为我喜欢在控制器调用最多的单独类中执行此操作的想法。

这实际上是一个设计问题 - 我在问什么方法实现这个最有意义?

2 个答案:

答案 0 :(得分:1)

您可以为此编写自定义HTML帮助程序。因此控制器操作将负责填充视图模型并将其传递给视图:

public ActionResult GetValueInput(Guid attributeFieldUid)
{
    AttributeField field = GetAttributeFieldFromDb(attributeFieldUid);
    AttributeViewModel viewModel = new AttributeViewModel();
    viewModel.FieldType = field.type;
    return View(viewModel);
}

然后写一个帮手:

public static class HtmlExtensions
{
    public static IHtmlString Field(this HtmlHelper html, FieldType type)
    {
        switch(field.type)
        {
            case Dropdown:
                return html.DropDownList(... you will probably need some more info on your view model to be passed here to generate a dropdown)
            case Text:
                return html.TextBox(...);
            case Date:
                return html.OurDatePicker();
        }

        return MvcHtmlString.Empty;
    }
}

此助手将在视图中使用:

@model AttributeViewModel
@Html.Field(Model.FieldType)

另一种可能性是使用编辑器模板。这是an example

答案 1 :(得分:0)

嗯听起来像是AOP的工作。

这很简单,创建一个自定义属性,您可以使用ex。

指定字段的类型。
public class CustomAttribute : Attribute
{
    private readonly FieldType _fieldType;
    public CustomAttribute(FieldType fieldType)
    {
        _fieldType = fieldType;
    }
    public FieldType FieldType { get { return _fieldType; } }
}

并在viewmodel ex。

上注释属性
[Custom(FieldType.CheckBox)]
public int SomeField { get; set; }

然后编写一个html帮助扩展方法ex。

public static class CustomHtmlHelperExtensions
{
    public MvcHtmlString CustomControlFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel,TProperty>> memberExpression)
    {
        var member = ((MemberExpression)model.Body).Member;
        var customAttribute = member.GetAttributes().OfType<CustomAttribute>().Cast<CustomAttribute>().SingleOrDefault();
        if(customAttribute == null)
        //Perform certain logic if the property doesn't have the attribute specified
        //ex. return null;
        switch(customAttribute.FieldType)
        {
            case FieldType.TextBox: 
                {
                    //Do something
                    return htmlHelper.TextBoxFor(memberExpression);
                }
            default: break;
        }
        return null;
    }
}

至少应该让你开始:)