如何使用模型中的自定义属性更改剃刀视图模型中的输入元素名称属性值?

Pro*_*ing 10 c# asp.net-mvc razor

我有以下内容:

@model Pharma.ViewModels.SearchBoxViewModel
<div class="smart-search">
    @using (Html.BeginForm("Index", "Search", FormMethod.Get, new { @class = "form-horizontal", role = "form" }))
    {
        <div class="form-group">
            <div class="hidden-xs- col-sm-1 col-md-1 col-lg-1 text-right">
                @Html.LabelFor(m => m.SearchPhrase, new { @class = "control-label" })
            </div>
            <div class="col-xs-8 col-sm-8 col-md-9 col-lg-10">
                @Html.TextBoxFor(m => m.SearchPhrase, new { @class = "form-control" })
            </div>
            <div class="col-xs-4 col-sm-3 col-md-2 col-lg-1">
                <input type="submit" value="Search" class="btn btn-default" />
            </div>
        </div>
    }
</div>
Run Code Online (Sandbox Code Playgroud)

如您所见,这是创建一个输入元素.

传递给视图的视图模型包含以下内容:

public class SearchBoxViewModel
{
    [Required]
    [Display(Name = "Search")]
    public string SearchPhrase { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

目前,input元素包含一个名为"SearchPhrase"的name属性,但我希望该值只是"q"而不重命名该属性.

我更喜欢一个扩展,它允许我调用TextBoxFor,但不需要提供Name属性,因此自定义属性以某种方式将Name属性的值自动设置为自定义属性中指定的值.

以下是我的意思的一个例子:

public class SearchBoxViewModel
{
    [Required]
    [Display(Name = "Search")]
    [Input(Name = "q")]
    public string SearchPhrase { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

结合:

@model Pharma.ViewModels.SearchBoxViewModel
<div class="smart-search">
    @using (Html.BeginForm("Index", "Search", FormMethod.Get, new { @class = "form-horizontal", role = "form" }))
    {
        <div class="form-group">
            <div class="hidden-xs- col-sm-1 col-md-1 col-lg-1 text-right">
                @Html.LabelFor(m => m.SearchPhrase, new { @class = "control-label" })
            </div>
            <div class="col-xs-8 col-sm-8 col-md-9 col-lg-10">
                @Html.TextBoxFor(m => m.SearchPhrase, new { @class = "form-control" })
            </div>
            <div class="col-xs-4 col-sm-3 col-md-2 col-lg-1">
                <input type="submit" value="Search" class="btn btn-default" />
            </div>
        </div>
    }
</div>
Run Code Online (Sandbox Code Playgroud)

然后会产生类似于以下内容:

<div class="smart-search">
    <form action="/Search/Index" method="get" class="form-horizontal" role="form">
        <div class="form-group">
            <div class="hidden-xs- col-sm-1 col-md-1 col-lg-1 text-right">
                <label for="Search" class="control-label">Search</label>
            </div>
            <div class="col-xs-8 col-sm-8 col-md-9 col-lg-10">
                <input type="text" name="q" id="Search" value="" class="form-control" />
            </div>
            <div class="col-xs-4 col-sm-3 col-md-2 col-lg-1">
                <input type="submit" value="Search" class="btn btn-default" />
            </div>
        </div>
    </form>
</div>
Run Code Online (Sandbox Code Playgroud)

我希望这个自定义属性在使用SearchBoxViewModel时生效,无论使用什么模板来防止错误,目的是让程序员清楚,同时为用户创建用户友好的查询字符串.

是否可以使用SearchPhrase属性上的自定义属性以与显示名称更改方式类似的方式执行此操作?

ali*_*ari 3

我写了一些简单的东西,但可以作为编写完整解决方案的开始。

首先,我Attribute用您提供的名称写了一个简单的:

public class InputAttribute : Attribute
{
    public string Name { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

然后我编写了一个 Html 帮助程序,它包装默认值TextBoxFor并搜索Input属性,如果有的话,它将替换生成HtmlString自的 name 属性TextBoxFor

public static MvcHtmlString MyTextBoxFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, System.Linq.Expressions.Expression<Func<TModel, TProperty>> expression, object htmlAttributes)
{
    var memberExpression = expression.Body as MemberExpression;

    var attr = memberExpression.Member.GetCustomAttribute(typeof (InputAttribute)) as InputAttribute;
    var result = htmlHelper.TextBoxFor(expression, htmlAttributes);
    if (attr != null)
    {
        var resultStr = result.ToString();
        var match = Regex.Match(resultStr, "name=\\\"\\w+\\\"");
        return new MvcHtmlString(resultStr.Replace(match.Value, "name=\"" + attr.Name + "\""));
    }

    return result;
}
Run Code Online (Sandbox Code Playgroud)

然后在 razor 视图中使用这个 html 助手:

@Html.MyTextBoxFor(m => m.SearchPhrase, new { @class = "form-control" })
Run Code Online (Sandbox Code Playgroud)

另外你的模型如下:

public class SearchBoxViewModel
{
    [Required]
    [Display(Name = "Search")]
    [Input(Name = "q")]
    public string SearchPhrase { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

这是完成解决方案的一种方法:

  1. 你必须实现所有的重载TextBoxFor
  2. 如果您尝试将表单数据发送到具有 类型参数的操作,SearchBoxViewModel您将收到 404,因为ModelBinder无法将请求参数绑定到 this ViewModel。所以你必须写一个ModelBinder来解决这个问题。
  3. 您必须LabelFor相应地编写才能正确匹配for属性。

编辑:如果出现问题,您不必处理情况 2,因为您发送请求GET,并且您将在查询字符串中获取表单参数。所以你可以这样写你的动作签名:

public ActionResult Search(string q)
{
  // use q to search
}
Run Code Online (Sandbox Code Playgroud)

当您的操作参数中有非基本类型时,就会出现问题。在这种情况下ModelBinder,尝试将查询字符串项(或请求负载)与操作参数类型的属性进行匹配。例如:

public ActionResult Search(SearchBoxViewModel vm)
{
  // ...
}
Run Code Online (Sandbox Code Playgroud)

在这种情况下,查询字符串(或请求负载)在名为的参数中包含您的搜索查询q(因为输入的名称是q,html 表单以由输入名称和输入值组成的键值形式发送请求)。所以MVC不能绑定qSearchPhrasein LoginViewModel,你会得到一个404。