Is it possible to create a generic @helper method with Razor?

后端 未结 4 1030
轻奢々
轻奢々 2020-11-28 03:25

I am trying to write a helper in Razor that looks like the following:

@helper DoSomething(Expression> expr) where T : clas         


        
相关标签:
4条回答
  • 2020-11-28 04:03

    In all cases the TModel will be the same (the model declared for the view), and in my case, the TValue was going to be the same, so I was able to declare the Expression argument type:

    @helper FormRow(Expression<Func<MyViewModel, MyClass>> expression) {
      <div class="form-group">
        @(Html.LabelFor(expression, new { @class = "control-label col-sm-6 text-right" }))
        <div class="col-sm-6">
          @Html.EnumDropDownListFor(expression, new { @class = "form-control" })
        </div>
        @Html.ValidationMessageFor(expression)
      </div>
    }
    

    If your model fields are all string, then you can replace MyClass with string.

    It might not be bad to define two or three helpers with the TValue defined, but if you have any more that would generate some ugly code, I didn't really find a good solution. I tried wrapping the @helper from a function I put inside the @functions {} block, but I never got it to work down that path.

    0 讨论(0)
  • 2020-11-28 04:12

    This is possible to achieve inside a helper file with the @functions syntax but if you want the razor-style readability you are referring to you will also need to call a regular helper to do the HTML fit and finish.

    Note that functions in a Helper file are static so you would still need to pass in the HtmlHelper instance from the page if you were intending to use its methods.

    e.g. Views\MyView.cshtml:

    @MyHelper.DoSomething(Html, m=>m.Property1)
    @MyHelper.DoSomething(Html, m=>m.Property2)
    @MyHelper.DoSomething(Html, m=>m.Property3)
    

    App_Code\MyHelper.cshtml:

    @using System.Web.Mvc;
    @using System.Web.Mvc.Html;
    @using System.Linq.Expressions;
    @functions
    {
        public static HelperResult DoSomething<TModel, TItem>(HtmlHelper<TModel> html, Expression<Func<TModel, TItem>> expr)
        {
            return TheThingToDo(html.LabelFor(expr), html.EditorFor(expr), html.ValidationMessageFor(expr));
        }
    }
    @helper TheThingToDo(MvcHtmlString label, MvcHtmlString textbox, MvcHtmlString validationMessage)
    {
        <p>
            @label
            <br />
            @textbox
            @validationMessage
        </p>
    }
    ...
    
    0 讨论(0)
  • 2020-11-28 04:19

    if your main problem is to get name attribute value for binding using lambda expression seems like the @Html.TextBoxFor(x => x.MyPoperty), and if your component having very complex html tags and should be implemented on razor helper, then why don't just create an extension method of HtmlHelper<TModel> to resolve the binding name:

    namespace System.Web.Mvc
    {
        public static class MyHelpers
        {
            public static string GetNameForBinding<TModel, TProperty>
               (this HtmlHelper<TModel> model, 
                Expression<Func<TModel, TProperty>> property)
            {
                return ExpressionHelper.GetExpressionText(property);
            }
        }
    }
    

    your razor helper should be like usual:

    @helper MyComponent(string name)
    {
        <input name="@name" type="text"/>
    }
    

    then here you can use it

    @TheHelper.MyComponent(Html.GetNameForBinding(x => x.MyProperty))
    
    0 讨论(0)
  • 2020-11-28 04:25

    No, this is not currently possible. You could write a normal HTML helper instead.

    public static MvcHtmlString DoSomething<T, U>(
        this HtmlHelper htmlHelper, 
        Expression<Func<T, U>> expr
    ) where T : class
    {
        ...
    }
    

    and then:

    @(Html.DoSomething<SomeModel, string>(x => x.SomeProperty))
    

    or if you are targeting the model as first generic argument:

    public static MvcHtmlString DoSomething<TModel, TProperty>(
        this HtmlHelper<TModel> htmlHelper, 
        Expression<Func<TModel, TProperty>> expr
    ) where TModel : class
    {
        ...
    }
    

    which will allow you to invoke it like this (assuming of course that your view is strongly typed, but that's a safe assumption because all views should be strongly typed anyways :-)):

    @Html.DoSomething(x => x.SomeProperty)
    
    0 讨论(0)
提交回复
热议问题