【发布时间】:2017-01-15 03:19:05
【问题描述】:
我正在创建一个助手,它允许我创建使用 AJAX 填充自己的级联下拉列表。辅助方法如下所示:
public static MvcHtmlString AjaxSelectFor<TModel, TProperty>(
this HtmlHelper<TModel> html,
Expression<Func<TModel, TProperty>> expression,
Expression<Func<TModel, TProperty>> cascadeFrom,
string sourceUrl,
bool withEmpty = false)
{
string controlFullName = html.GetControlName(expression);
string cascadeFromFullName = html.GetControlName(cascadeFrom);
var selectBuilder = GetBaseSelect(controlFullName.GetControlId(), controlFullName, sourceUrl, withEmpty);
selectBuilder.Attributes.Add("data-selected-id", html.GetValue(expression));
selectBuilder.Attributes.Add("data-cascade-from", "#" + cascadeFromFullName.GetControlId());
return new MvcHtmlString(selectBuilder.ToString());
}
private static TagBuilder GetBaseSelect(string controlId, string controlName, string sourceUrl, bool withEmpty)
{
var selectBuilder = new TagBuilder("select");
selectBuilder.Attributes.Add("id", controlId);
selectBuilder.Attributes.Add("name", controlName);
selectBuilder.Attributes.Add("data-toggle", "ajaxSelect");
selectBuilder.Attributes.Add("data-source-url", sourceUrl);
selectBuilder.Attributes.Add("data-with-empty", withEmpty.ToString());
selectBuilder.AddCssClass("form-control");
return selectBuilder;
}
internal static string GetControlName<TModel, TProperty>(this HtmlHelper<TModel> html, Expression<Func<TModel, TProperty>> expression)
{
string controlName = ExpressionHelper.GetExpressionText(expression);
return html.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldName(controlName);
}
internal static string GetControlId(this string controlName)
{
return TagBuilder.CreateSanitizedId(controlName);
}
第一个表达式针对将在控件中绑定的属性,我可以毫无问题地获取它的 id 和 name 属性。第二个目标是帮助器将级联的属性,但是当我通过 GetControlName 方法时,ExpressionHelper.GetExpressionText(expression) 返回一个空字符串而不是属性名称。我在“表达式”上添加了一个手表来检查出了什么问题,它的值如下:
{model => Convert(model.TopCategoryId)}
当我获取第一个表达式的属性名称时,我得到以下值:
{model => model.CategoryId}
我真的不明白为什么这两种表达方式之间存在差异。这是我在视图中调用助手的方式,以防它无论如何都相关:
@Html.AjaxSelectFor(model => model.CategoryId, model => model.TopCategoryId, "/api/Categories/GetSelectList", true)
知道这里发生了什么吗?
【问题讨论】:
-
您确实意识到这永远不会为您提供正确的 2 路模型绑定,也不会提供客户端验证。
-
不,我没有。实际上,我没有太多创建自己的数据绑定助手的经验。你碰巧有一些关于这个主题的有用文档吗?
-
首先,问题是
expression中的TProperty与方法签名中的TProperty相同(OK),但cascadeFrom中的TProperty不是所以它不可能是已解决。 -
我强烈建议您在尝试编写自己的方法之前研究source code 的
HtmlHelper方法,并且您编写的任何扩展方法都应尽可能利用现有的内置方法。 -
您似乎想要做的只是生成其他属性,因此您应该只使用
return html.DropDownListFor(...)和接受htmlAttributes的重载之一。举个简单的例子,参考this answer
标签: c# asp.net-mvc html-helper linq-expressions