0

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

我的问题:我想在选择适当的属性字段时在控制器动作中声明一个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 语句。但我想我喜欢在控制器最常调用的单独类中执行此操作的想法。

这真的是一个设计问题——我在问什么方法来实现这个最有意义?

4

2 回答 2

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)

另一种可能性是使用编辑器模板。这是一个例子

于 2012-04-26T06:08:33.187 回答
0

嗯,听起来像是 AOP 的工作。

这很简单,创建一个自定义属性,您可以在其中指定字段的类型以及所需的任何其他参数,例如。

public class CustomAttribute : Attribute
{
    private readonly FieldType _fieldType;
    public CustomAttribute(FieldType fieldType)
    {
        _fieldType = fieldType;
    }
    public FieldType FieldType { get { return _fieldType; } }
}

并在视图模型上注释属性。

[Custom(FieldType.CheckBox)]
public int SomeField { get; set; }

然后编写一个 html helper 扩展方法 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;
    }
}

这至少应该让你开始:)

于 2012-04-27T20:18:37.480 回答