-1

从视觉上讲,在我的一个 MVC 视图中,我有大约 20 个以标准垂直顺序排列的字段,前 8 个左右的字段在<div>右侧的同一组中具有可选的 [创建] 框。

我的默认选项卡顺序目前点击我的第一个下拉菜单,然后直接进入 [创建],向下到下一个,然后向右等等。我想做的是将 TAB 顺序设置为它直接向下进入我的各个字段的位置并离开[创建] 框作为用户可选(或在标签顺序的末尾)。尽管通过快速搜索似乎对此进行了很多讨论,但答案似乎不一致;其中很多似乎是几年前关于设置 TAB 顺序EditorFor()但被迫使用自定义编辑器模板或切换到TextBoxFor()

希望有人可以权衡一下。下面详细介绍了我的字段:

(8 of these DropDownListFor()):
@Html.DropDownListFor(model => model.STATUS_ID, (SelectList)ViewBag.Model_List, htmlAttributes: new { @class = "form-control dropdown", @id = "selectStatus" })

(12 of these EditorFor()):
@Html.EditorFor(model => model.NOTE, new { htmlAttributes = new { @class = "form-control" } })
4

1 回答 1

3

要设置 Tab 键顺序,您需要做的就是tabindex向生成的字段添加一个额外的属性。TextBoxFor使用or之类的东西就很容易了DropDownListFor,因为它们实际上htmlAttributes专门为此目的使用了一个参数:

@Html.TextBoxFor(m => m.Foo, new { tabindex = 1 })

在过去,同样不能这么说EditorFor。由于它是一个“模板化”帮助器,编辑器模板,而不是方法调用,会影响生成的内容。您可以在 的定义中看到这一点EditorFor,因为没有htmlAttributes像其他助手那样的参数,而是additionalViewData.

从 MVC 5.1 开始,Microsoft 可以EditorFor通过特殊命名的ViewData键将额外的 HTML 属性传递给"htmlAttributes". 结果,您可以实现与使用类似的东西时相同的效果TextBoxFor,尽管它有点冗长:

@Html.EditorFor(m => m.Foo, new { htmlAttributes = new { tabindex = 1 } })

看,你实际上仍然在additionalViewData这里传递,但是额外的视图数据包含一个匿名对象,键为htmlAttributes. 然后,内置的编辑器模板知道如何利用ViewData["htmlAttributes"]来向生成的元素添加额外的属性。但是,这仅适用于默认编辑器模板,因为 Microsoft 已专门对它们进行了编程以使用它。一旦您添加了自己的自定义编辑器模板,您就回到了开始的地方。

您可以通过多种方式使用自定义编辑器模板来解决此问题。首先,您可以直接将选项卡索引作为视图数据传递,并在模板中使用它:

@Html.EditorFor(m => m.Foo, new { tabindex = 1 })

然后,在您的编辑器模板中:

@Html.TextBox("", ViewData.TemplateInfo.FormattedModelValue, new { tabindex = ViewData["tabindex"]})

EditorFor其次,您可以使用默认模板模仿的行为:

@Html.EditorFor(m => m.Foo, new { htmlAttributes = new { tabindex = 1 } })

然后,在您的编辑器模板中:

@Html.TextBox("", ViewData.TemplateInfo.FormattedModelValue, ViewData["htmlAttributes"])

但是,该选项不允许您拥有“默认”属性。这是一种全有或全无的方法。为了真正能够ViewData["htmlAttributes"]像内置编辑器模板那样使用,您需要首先将默认属性与传入的属性结合起来,然后将整个 shebang 传递给htmlAttributes. 我有一篇博文对此进行了深入讨论,但是 TL;DR:您需要以下扩展:

using System.Collections.Generic;
using System.Linq;
using System.Web.Mvc;
using System.Web.Routing;

public static partial class HtmlHelperExtensions
{
    public static IDictionary<string, object> MergeHtmlAttributes(this HtmlHelper helper, object htmlAttributesObject, object defaultHtmlAttributesObject)
    {
        var concatKeys = new string[] { "class" };

        var htmlAttributesDict = htmlAttributesObject as IDictionary<string, object>;
        var defaultHtmlAttributesDict = defaultHtmlAttributesObject as IDictionary<string, object>;

        RouteValueDictionary htmlAttributes = (htmlAttributesDict != null)
            ? new RouteValueDictionary(htmlAttributesDict)
            : HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributesObject);
        RouteValueDictionary defaultHtmlAttributes = (defaultHtmlAttributesDict != null)
            ? new RouteValueDictionary(defaultHtmlAttributesDict)
            : HtmlHelper.AnonymousObjectToHtmlAttributes(defaultHtmlAttributesObject);

        foreach (var item in htmlAttributes)
        {
            if (concatKeys.Contains(item.Key))
            {
                defaultHtmlAttributes[item.Key] = (defaultHtmlAttributes[item.Key] != null)
                    ? string.Format("{0} {1}", defaultHtmlAttributes[item.Key], item.Value)
                    : item.Value;
            }
            else
            {
                defaultHtmlAttributes[item.Key] = item.Value;
            }
        }

        return defaultHtmlAttributes;
    }
}

然后您需要将以下内容添加到自定义编辑器模板的顶部:

@{
    var defaultHtmlAttributesObject = new { type = "date", @class = "form-control" };
    var htmlAttributesObject = ViewData["htmlAttributes"] ?? new { };
    var htmlAttributes = Html.MergeHtmlAttributes(htmlAttributesObject, defaultHtmlAttributesObject);
}

您将defaultHtmlAttributesObject根据生成的输入对于该特定模板默认应具有的属性来更改变量。

于 2015-12-31T19:18:53.693 回答