使用@Html.EditorFor(model =>model.IsClient)
,其中IsClient是布尔值,使用Not Set, Yes and No
作为选项呈现下拉列表。
一切都很好。
现在我想将knockoutjs与我喜欢的结果下拉列表一起使用,那么如何使用@ Html.EditorFor添加data-bind属性,我需要使用knockoutjs来处理这个下拉列表?
我试过了:
@Html.EditorFor(model => model.IsClient, new Dictionary<string, object> { { "data-bind", "value: Account.IsClient" } })
但是,它使用对象additionalViewData参数,并且它不呈现data-bind属性。这可能很自然,因为此参数可能与渲染标记的Html属性无关。
但是,找不到任何合理的文档,其他任何重载都不适合我想要的东西。
任何建议。
答案 0 :(得分:9)
Brad Wilson blogged关于ASP.NET MVC 2中的显示和编辑器模板。因此,您可以修改布尔值的默认模板并添加所需的属性(~/Views/Shared/EditorTemplates/MyTemplate.cshtml
):
@{
bool? value = null;
if (ViewData.Model != null)
{
value = Convert.ToBoolean(ViewData.Model, System.Globalization.CultureInfo.InvariantCulture);
}
var triStateValues = new List<SelectListItem>
{
new SelectListItem
{
Text = "Not Set",
Value = String.Empty,
Selected = !value.HasValue
},
new SelectListItem
{
Text = "True",
Value = "true",
Selected = value.HasValue && value.Value
},
new SelectListItem
{
Text = "False",
Value = "false",
Selected = value.HasValue && !value.Value
},
};
}
@if (ViewData.ModelMetadata.IsNullableValueType)
{
<!-- TODO: here you can use any attributes you like -->
@Html.DropDownList(
"",
triStateValues,
new {
@class = "list-box tri-state",
data_bind="value: " + ViewData.TemplateInfo.GetFullHtmlFieldName("") // you could also use ViewData.ModelMetadata.PropertyName if you want to get only the property name and not the entire navigation hierarchy name
}
)
}
else
{
@Html.CheckBox("", value ?? false, new { @class = "check-box" })
}
最后:
@Html.EditorFor(model => model.IsClient, "MyTemplate")
或使用UIHint
属性装饰视图模型上的IsClient属性:
[UIHint("MyTemplate")]
public bool? IsClient { get; set; }
然后:
@Html.EditorFor(x => x.IsClient)
将自动选择自定义编辑器模板。
答案 1 :(得分:5)
@Darin Dimitrov的答案很棒,但是对于knockoutjs来说有点过于严格,其中复杂的视图可能导致viewModel没有完全映射到@Model参数。
所以我已经使用了对象additionalViewData参数。要从Custom EditorTemplate访问additionalViewData参数,请参阅以下SO问题:
Access additionalViewData from Custom EditorTemplate code
<强>题外话: additionalViewData参数令人困惑,因为它对默认编辑器没有任何作用。它只能通过自定义编辑器模板实现。
无论如何,我对Darin代码的修改如下:
@if (ViewData.ModelMetadata.IsNullableValueType)
{
var x = ViewData["koObservablePrefix"];
if ((x != "") && (x != null)) { x = x + "."; }
@Html.DropDownList(
"",
triStateValues,
new {
@class = "list-box tri-state",
data_bind="value: " + x + ViewData.TemplateInfo.GetFullHtmlFieldName("") // or you could also use ViewData.ModelMetadata.PropertyName if you want to get only the property name and not the entire navigation hierarchy name
}
)
}
else
{
@Html.CheckBox("", value ?? false, new { @class = "check-box" })
}
注意以下几行:
var x = ViewData["koObservablePrefix"];
if ((x != "") && (x != null)) { x = x + "."; }
koObservablePrefix就在那里,我可以在viewModel ko.observable中添加任意前缀。如果您愿意,可以做其他事情。
我使用变量x如下:
data_bind="value: " + x + ViewData.TemplateInfo.GetFullHtmlFieldName("")
这样,如果我没有传入additionalViewData“koObservablePrefix”,它仍然有效。
所以,现在我可以写:
@Html.EditorFor(model => model.IsClient, "koBoolEditorFor", new { koObservablePrefix = "Account" })
将呈现为:
<select class="list-box tri-state" data-bind="value: Account.IsBank" id="IsBank" name="IsBank">
请注意“值:Account.IsBank”数据绑定属性值。
例如,如果您的视图强类型模型属于Account类型,但在您的页面的accountViewModel中,您的结构更复杂,则需要将您的observable打包在帐户对象中。 EG:
function account(accountId, personId, accountName, isClient, isProvider, isBank) {
this.AccountId = ko.observable(accountId);
this.PersonId = ko.observable(personId);
this.AccountName = ko.observable(accountName);
this.IsClient = ko.observable(isClient);
this.IsProvider = ko.observable(isProvider);
this.IsBank = ko.observable(isBank);
}
function accountViewModel() {
var self = this;
this.selectedCostCentre = ko.observable('');
this.Account = new account(@Model.AccountId, @Model.PersonId, '@Model.AccountName', '@Model.IsClient','@Model.IsProvider', '@Model.IsBank');
// etc. etc
}
如果你没有这种结构,那么代码将获取结构。这只是将viewModel js定制为这个,非常灵活的约定。
希望这不会太混乱......