从Razor助手中获取模型

时间:2012-12-25 00:10:29

标签: asp.net-mvc-3 razor

有没有办法将视图模型传递给@helper函数?

我有一个自定义编辑器,显示Yes / No / Maybe单选按钮。该编辑器的代码如下所示。由于它需要一个自定义函数加上3行代码来显示每个单选按钮,我想封装在全局@helper函数中创建每个单选按钮及其相关标签的代码,但我无法弄清楚如何将RadioButtonFor移动到全局辅助函数中。

鲍勃

这是现有代码:

@model System.String

@functions {
    // Returns an anonymous object that specifies the radio button HTML options
    private object HTMLOptions(string id, bool @checked) {
        if (@checked) {
            return new { id, @checked = "checked" };
        } else {
            return new { id };
        }
    }
}

@{
    string value = Model + "";
    string id;
}

<div class="option-list">
    @{id = ViewData.TemplateInfo.GetFullHtmlFieldId("radioYes");}
    @Html.RadioButtonFor(q => q, "true", HTMLOptions(id, value == "true"))
    @Html.LabelFor(q => q, "Yes", new {@for = id})
    <br />

    @{id = ViewData.TemplateInfo.GetFullHtmlFieldId("radioNo");}
    @Html.RadioButtonFor(q => q, "false", HTMLOptions(id, value == "false"))
    @Html.LabelFor(q => q, "No", new {@for = id})
    <br />

    @{id = ViewData.TemplateInfo.GetFullHtmlFieldId("radioMaybe");}
    @Html.RadioButtonFor(q => q, "maybe", HTMLOptions(id, value == "maybe"))
    @Html.LabelFor(q => q, "Maybe", new {@for = id})
    <br />
</div>

我希望能够在一次调用中编写一个封装RadioButtonFor和LabelFor的通用助手,以及我的附加代码以包含“checked”属性,如下所示:

@model something

<div class="option-list">
    @MyRadioButtonAndLabelFor(q => something.x, "Yes",   "true") @* (model, label, value) *@
    @MyRadioButtonAndLabelFor(q => something.x, "No",    "false")
    @MyRadioButtonAndLabelFor(q => something.x, "Maybe", "maybe")
</div>

1 个答案:

答案 0 :(得分:2)

试试这样:

@model System.String

@functions {
    private object HtmlAttributes(string id, string model, string value) {
        if (model == value) {
            return new { id, @checked = "checked" };
        }

        return new { id };
    }
}

@helper Radios(HtmlHelper<string> html) {
    var model = html.ViewData.Model;

    @html.RadioButtonFor(q => q, "true", HtmlAttributes("yes", model, "true"))
    @Html.LabelFor(q => q, "Yes", new { @for = "yes" })
    <br/>

    @html.RadioButtonFor(q => q, "false", HtmlAttributes("no", model, "false"))
    @Html.LabelFor(q => q, "No", new { @for = "no" })
    <br/>

    @html.RadioButtonFor(q => q, "maybe", HtmlAttributes("maybe", model, "maybe"))
    @Html.LabelFor(q => q, "Maybe", new { @for = "maybe" })
    <br/>
}

<div class="option-list">
    @Radios(Html)
</div>

<击>


更新:

似乎我误解了你的问题。更新后,我更了解您要实现的目标。为了实现它,你可以编写一个自定义的Html帮助器:

using System;
using System.Linq.Expressions;
using System.Text;
using System.Web;
using System.Web.Mvc;
using System.Web.Mvc.Html;

public static class HtmlExtensions
{
    public static IHtmlString MyRadioButtonAndLabelFor<TModel, TValue>(
        this HtmlHelper<TModel> htmlHelper,
        Expression<Func<TModel, TValue>> expression,
        string label,
        object value
    )
    {
        var name = ExpressionHelper.GetExpressionText(expression);
        var id = htmlHelper.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldId(
            name + value
        );
        var sb = new StringBuilder();
        sb.Append(htmlHelper.RadioButtonFor(expression, value, new { id = id }));
        var labelTag = new TagBuilder("label");
        labelTag.SetInnerText(label);
        labelTag.Attributes["for"] = id;
        sb.Append(labelTag.ToString());
        return new HtmlString(sb.ToString());
    }
}

然后你可以有一个视图模型:

public class MyViewModel
{
    public string Value { get; set; }
}

控制器:

public class HomeController : Controller
{
    public ActionResult Index()
    {
        return View(new MyViewModel
        {
            Value = "false"
        });
    }
}

和相应的观点:

@model MyViewModel

<div class="option-list">
    @Html.MyRadioButtonAndLabelFor(q => q.Value, "Yes",   "true")
    @Html.MyRadioButtonAndLabelFor(q => q.Value, "No",    "false")
    @Html.MyRadioButtonAndLabelFor(q => q.Value, "Maybe", "maybe")
</div>

备注:为了将MyRadioButtonAndLabelFor自定义扩展方法引入范围,您需要添加名称空间,其中包含的类(HtmlExtensions)已在您的命名空间标记中声明~/Views/web.config(不是~/web.config)或在视图中添加@using ...指令。


如果您愿意,还可以在Razor视图中定义内联帮助:

@functions {
    public IHtmlString MyRadioButtonAndLabelFor<TModel, TValue>(
        HtmlHelper<TModel> htmlHelper,
        System.Linq.Expressions.Expression<Func<TModel, TValue>> expression,
        string label,
        object value
    )
    {
        var name = ExpressionHelper.GetExpressionText(expression);
        var id = htmlHelper.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldId(name + value);

        var sb = new StringBuilder();
        sb.Append(htmlHelper.RadioButtonFor(expression, value, new { id = id }));
        var labelTag = new TagBuilder("label");
        labelTag.SetInnerText(label);
        labelTag.Attributes["for"] = id;
        sb.Append(labelTag.ToString());

        return new HtmlString(sb.ToString());
    }
}

然后像这样使用它:

<div class="option-list">
    @MyRadioButtonAndLabelFor(Html, q => q.Value, "Yes",   "true")
    @MyRadioButtonAndLabelFor(Html, q => q.Value, "No",    "false")
    @MyRadioButtonAndLabelFor(Html, q => q.Value, "Maybe", "maybe")
</div>

就Razor助手而言(@helper定义),嗯,他们不能是通用的,因此你将有麻烦宣布这样的结构。