我有以下内容:
@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>
正如您所看到的,这是创建一个输入元素。
传递给视图的视图模型包含以下内容:
public class SearchBoxViewModel
{
[Required]
[Display(Name = "Search")]
public string SearchPhrase { get; set; }
}
目前,input元素包含一个name属性,其值为&#34; SearchPhrase&#34;但我希望价值只是&#34; q&#34;没有重命名属性。
我更喜欢一个扩展,它允许我调用TextBoxFor,但不需要提供Name属性,因此自定义属性会以某种方式将Name属性的值自动设置为自定义属性中指定的值。 / p>
以下是我的意思的一个例子:
public class SearchBoxViewModel
{
[Required]
[Display(Name = "Search")]
[Input(Name = "q")]
public string SearchPhrase { get; set; }
}
结合:
@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>
然后会产生类似于以下内容的内容:
<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>
我希望这个自定义属性在使用SearchBoxViewModel时生效,无论使用什么模板来防止错误,目的是让程序员清楚,同时为用户创建用户友好的查询字符串。
是否可以使用SearchPhrase属性上的自定义属性以与显示名称更改方式类似的方式执行此操作?
答案 0 :(得分:3)
我写了一些简单的东西,但可以开始编写完整的解决方案。
首先,我用你提供的名字写了一个简单的Attribute
:
public class InputAttribute : Attribute
{
public string Name { get; set; }
}
然后我编写了一个包含默认TextBoxFor
的Html帮助器并搜索Input
属性,如果有的话,它将从HtmlString
替换生成的TextBoxFor
的名称属性:< / p>
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;
}
然后在剃刀视图中使用此html帮助器:
@Html.MyTextBoxFor(m => m.SearchPhrase, new { @class = "form-control" })
您的模型如下:
public class SearchBoxViewModel
{
[Required]
[Display(Name = "Search")]
[Input(Name = "q")]
public string SearchPhrase { get; set; }
}
这是一种完成解决方案的方法:
TextBoxFor
SearchBoxViewModel
的操作,则会得到404,因为ModelBinder
无法将请求参数绑定到此ViewModel
。所以你必须写一个ModelBinder
来解决这个问题。LabelFor
以正确匹配for
属性。 编辑:如果您遇到问题,则不必处理案例2,因为您发送了GET
请求,您将在查询字符串中获取表单参数。所以你可以写下你的行动签名:
public ActionResult Search(string q)
{
// use q to search
}
如果操作参数中包含非基本类型,则会出现此问题。在这种情况下,ModelBinder
尝试将查询字符串项(或请求有效内容)与操作类型参数的属性进行匹配。例如:
public ActionResult Search(SearchBoxViewModel vm)
{
// ...
}
在这种情况下,查询字符串(或请求有效负载)在名为q
的参数中包含您的搜索查询(因为输入名称为q
,而html表单以键值组成的形式发送请求输入名称和输入值)。因此,MVC无法将q
绑定到SearchPhrase
中的LoginViewModel
,您将获得404.
答案 1 :(得分:3)
我知道这不是你明确要求的,但我觉得从实际的表单名称中获得一个不同的ViewModel名称会破坏MVC中的一个核心约定,可能会产生误导。
作为替代方案,您只需向反映SearchPhrase并具有正确名称的VM添加新属性:
public class SearchBoxViewModel
{
[Required]
[Display(Name = "Search")]
public string SearchPhrase { get; set; }
[Display(Name = "Search")]
public string q
{
get { return SearchPhrase; }
set { SearchPhrase = value; }
}
}
更改您的观点以使用这些:
@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.q, new { @class = "control-label" })
</div>
<div class="col-xs-8 col-sm-8 col-md-9 col-lg-10">
@Html.TextBoxFor(m => m.q, 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>
这样您就可以将代码保留在后端引用SearchPhrase
而不是q
,以便让程序员更轻松。希望这种观点不会散布到任何地方,你只有一个EditorTemplate或部分。