问题描述
从视觉上讲,在我的一个MVC视图中,我大约有20个字段以标准的垂直顺序排列,前8个左右的字段在右侧的同一<div>
组中具有可选的[创建]框.
Visually speaking, on one of my MVC Views I have about 20 fields in standard vertical order, with the first 8 or so having optional [Create] boxes in same <div>
group over on the right.
我的默认选项卡顺序当前命中我的第一个下拉列表,然后右移至[创建],向下移至下一个,然后右移,依此类推.我想将TAB顺序设置为在各个字段中均沿其垂直方向移动并将[创建]框保留为用户可选(或在制表符顺序的末尾).快速搜索似乎引起了很多讨论,但答案似乎不一致.似乎是几年前的许多问题,涉及在EditorFor()
中设置TAB顺序,但被迫使用自定义编辑器模板"或切换到TextBoxFor()
?
My default tab order currently hits my first dropdown, then goes right to [Create], down to the next, then right, etc. What I would like to do set the TAB order to where it goes straight down my various fields and leave the [Create] boxes as optional for the user (or at the end of the tab order). While there seems to be a lot of discussion on this with a quick search, there seems to be inconsistent answers; a lot of them seemingly from a couple years ago regarding setting TAB Order in an EditorFor()
but being forced to use Custom Editor Templates or switch to TextBoxFor()
?
希望有人可以对此加以考虑.以下稍微详细介绍了我的字段:
Hoping someone can weigh in on this. The below somewhat details my fields:
(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" } })
推荐答案
要设置选项卡顺序,您需要做的就是向生成的字段添加一个额外的属性tabindex
.对于TextBoxFor
或DropDownListFor
之类的东西,这已经足够简单了,因为它们实际上采用了专门为此目的的htmlAttributes
参数:
To set the tab order, all you need to do is be able to add an extra attribute, tabindex
to the generated field. That's easy enough with something like TextBoxFor
or DropDownListFor
, since they actually take an htmlAttributes
parameter specifically for this purpose:
@Html.TextBoxFor(m => m.Foo, new { tabindex = 1 })
过去,对于EditorFor
不能这么说.由于它是模板化"的帮助程序,因此编辑器模板而不是方法调用会影响所生成的内容.您可以在EditorFor
的定义中看到这一点,因为没有像其他助手一样的htmlAttributes
参数,而是additionalViewData
.
In the past, the same could not be said for EditorFor
. Since it's a "templated" helper, the editor template, not the method call, effects what's generated. You can see this in the definition of EditorFor
, as there's no htmlAttributes
param like the other helpers have, but rather additionalViewData
.
从MVC 5.1开始,Microsoft使得可以通过特殊命名的ViewData
键"htmlAttributes"
将其他HTML属性传递给EditorFor
.结果,您可以实现与使用TextBoxFor
之类的东西相同的功能,尽管它有些冗长:
Starting with MVC 5.1, Microsoft made it possible to pass additional HTML attributes to EditorFor
, via a specially named ViewData
key, "htmlAttributes"
. As a result, you can achieve the same thing as when using something like TextBoxFor
, although it's a little more verbose:
@Html.EditorFor(m => m.Foo, new { htmlAttributes = new { tabindex = 1 } })
看,您实际上仍然在这里传递additionalViewData
,但是该附加视图数据包含一个键为htmlAttributes
的匿名对象.然后,内置编辑器模板就会知道如何利用ViewData["htmlAttributes"]
向生成的元素添加其他属性.但是,这仅适用于默认编辑器模板,因为Microsoft专门对其进行了编程以使用此模板.添加您自己的自定义编辑器模板后,您就回到了开始的位置.
See, you're still actually passing additionalViewData
here, but that additional view data contains an anonymous object keyed to htmlAttributes
. The built-in editor templates, then, know how to utilize ViewData["htmlAttributes"]
to add additional attributes to the generated element. However, this only applies to the default editor templates because Microsoft has specifically programmed them to use this. As soon as you add your own custom editor templates, you're right back to where you started.
使用自定义编辑器模板可以采用多种方法.首先,您可以直接将标签索引作为视图数据传递,并在模板中加以利用:
There's a number of ways you could approach this with custom editor templates. First, you could just pass the tab index directly as view data, and utilize that in your template:
@Html.EditorFor(m => m.Foo, new { tabindex = 1 })
然后,在您的编辑器模板中:
Then, in your editor template:
@Html.TextBox("", ViewData.TemplateInfo.FormattedModelValue, new { tabindex = ViewData["tabindex"]})
第二,您可以使用默认模板模仿EditorFor
的行为:
Second, you could mimic EditorFor
's behavior with the default templates:
@Html.EditorFor(m => m.Foo, new { htmlAttributes = new { tabindex = 1 } })
然后,在您的编辑器模板中:
Then, in your editor template:
@Html.TextBox("", ViewData.TemplateInfo.FormattedModelValue, ViewData["htmlAttributes"])
但是,该选项不允许您具有默认"属性.这是一种全有或全无的方法.为了像内置编辑器模板那样真正地利用ViewData["htmlAttributes"]
,您需要首先将默认属性与传入的属性组合在一起,然后将整个shebang传递给htmlAttributes
.我有一个博客文章,其中对此进行了深入的讨论,但TL; DR:您将需要以下扩展名:
However, that option doesn't allow you to have "default" attributes. It's an all or nothing approach. To truly be able to utilize ViewData["htmlAttributes"]
as the built-in editor templates do, you'll need to combine the default attributes with the passed in ones, first, and then pass the whole shebang to htmlAttributes
. I've got a blog post that discusses that in depth, but TL;DR: you'll need the following extension:
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;
}
}
然后,您需要在自定义编辑器模板的顶部添加以下内容:
And then you'll need to add the following to top of your custom editor templates:
@{
var defaultHtmlAttributesObject = new { type = "date", @class = "form-control" };
var htmlAttributesObject = ViewData["htmlAttributes"] ?? new { };
var htmlAttributes = Html.MergeHtmlAttributes(htmlAttributesObject, defaultHtmlAttributesObject);
}
您将根据特定模板所生成的输入默认具有的属性来更改defaultHtmlAttributesObject
变量.
You'd change the defaultHtmlAttributesObject
variable depending on what attributes the generated input should have by default for that particular template.
这篇关于使用DropDownListFor()/EditorFor()在MVC视图上设置TAB顺序?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!