Có thể tạo phương thức @helper chung với Razor không?


88

Tôi đang cố gắng viết một trợ giúp trong Razor trông giống như sau:

@helper DoSomething<T, U>(Expression<Func<T, U>> expr) where T : class

Thật không may, trình phân tích cú pháp cho rằng đó <Tlà phần khởi đầu của một phần tử HTML và tôi kết thúc với một lỗi cú pháp. Có thể tạo trợ giúp với Razor là một phương pháp chung không? Nếu vậy, cú pháp là gì?


Vẫn chưa được sửa trong bản phát hành MVC 4 hiện tại. :(
Alex Dresko

1
Làm thế nào điều này vẫn chưa được khắc phục trong VS2012?
Alex Dresko 9/10/12

7
Chúa ơi, tôi không thể chờ đợi điều này được thêm vào; Tôi hy vọng điều này nằm ở đâu đó xung quanh " thực hiện nó ngày hôm qua " trong danh sách ưu tiên. Một phần hơi lạc đề, nhưng cùng với điều này, tôi muốn thấy rằng các lớp được tạo static, trừ khi các chi tiết triển khai cấm nó; Lý do là, là người ta có thể sử dụng những người giúp đỡ gia hạn chung :@helper Foo<T>(this T o) where T : IBar { }
Dan lugg

Câu trả lời:


52

Không, điều này là không thể. Thay vào đó, bạn có thể viết một trình trợ giúp HTML bình thường.

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

và sau đó:

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

hoặc nếu bạn đang nhắm mục tiêu mô hình dưới dạng đối số chung đầu tiên:

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

điều này sẽ cho phép bạn gọi nó như thế này (tất nhiên giả sử rằng chế độ xem của bạn được gõ mạnh, nhưng đó là một giả định an toàn vì mọi chế độ xem dù sao cũng nên được gõ mạnh :-)):

@Html.DoSomething(x => x.SomeProperty)

10
Hy vọng rằng đây là thứ mà họ thêm vào phiên bản trợ giúp Razor trong tương lai. Khả năng đọc của trình trợ giúp truyền thống thấp hơn nhiều so với cú pháp @helper.
mkedobbs

2
Yeah đồng ý. Hoàn nguyên về phương pháp cũ hơn không chỉ tệ mà còn chia rẽ những người trợ giúp của bạn một cách tùy tiện!
George R

126

Đây có thể đạt được bên trong một tập tin helper với @functionscú pháp nhưng nếu bạn muốn có thể đọc như dao cạo phong cách bạn đang đề cập đến bạn cũng sẽ cần phải gọi một helper thường xuyên để thực hiện phù hợp với HTML và kết thúc.

Lưu ý rằng các hàm trong tệp trợ giúp là tĩnh, vì vậy bạn vẫn cần phải chuyển vào phiên bản HtmlHelper từ trang nếu bạn định sử dụng các phương thức của nó.

ví dụ: 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>
}
...

Đây là hoàn hảo. Cảm ơn.
Ken Smith

Bạn không cần phải thực hiện phương pháp tĩnh, và do đó bạn cũng không cần phải vượt qua bạn Html / Url / mẫu vv
Sheepy

12
@Sheepy, điều đó chỉ đúng một nửa. Bạn đúng, bạn có thể làm cho chúng không tĩnh, nhưng bạn chỉ nhận được System.Web.WebPages.Html.HtmlHelperchứ không phải System.Web.Mvc.HtmlHelper. Có một cơ hội tuyệt vời là WebPagesphiên bản đó sẽ không phù hợp với bạn, vì hầu hết các phương pháp mở rộng được viết chống lạiSystem.Web.Mvc.HtmlHelper . Hơn nữa, không có thuộc Urltính và UrlHelperyêu cầu RequestContextthuộc tính không có trong WebPagesphiên bản. Tất cả những gì bạn có thể sẽ phải vượt qua trong Mvc HtmlHelper.
Kirk Woll

1
helper phải là một phần của App_Code Folder ??
Vishal Sharma

1
Có, tệp này phải được đặt trong {MyMvcProject}\App_Code`. It doesn't work as advertised when you place it elsewhere. The error *Cannot access non-static method 'TheThingToDo' in static context* disappears when you move MyHelper.cshtml` vào App_Code. DoSomethingphải tĩnh để bạn có thể gọi @MyHelper.DoSomething(..)trong chế độ xem của mình. Nếu bạn làm cho nó không tĩnh, trước tiên bạn cần tạo một phiên bản MyHelper.
Grilse

3

Trong tất cả các trường hợp, TModelsẽ giống nhau (mô hình được khai báo cho khung nhìn), và trong trường hợp của tôi, TValuesẽ giống nhau, vì vậy tôi có thể khai báo kiểu đối số Biểu thức:

@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>
}

Nếu các trường mô hình của bạn là tất cả string, thì bạn có thể thay thế MyClassbằng string.

Có thể không tồi nếu xác định hai hoặc ba trình trợ giúp với TValueđịnh nghĩa đã xác định, nhưng nếu bạn có thêm bất kỳ trình trợ giúp nào nữa sẽ tạo ra một số mã xấu xí, tôi thực sự không tìm ra giải pháp tốt. Tôi đã thử gói @helpertừ một hàm tôi đặt bên trong @functions {}khối, nhưng tôi không bao giờ làm cho nó hoạt động theo đường dẫn đó.


Đây là điều hiển nhiên khi bạn nghĩ về nó - nếu đó là điều TModelbạn có thể biết trước.
ta.speot.is

0

nếu vấn đề chính của bạn là lấy giá trị thuộc tính tên để liên kết bằng cách sử dụng biểu thức lambda @Html.TextBoxFor(x => x.MyPoperty)và nếu thành phần của bạn có các thẻ html rất phức tạp và phải được triển khai trên trình trợ giúp dao cạo, thì tại sao không chỉ tạo một phương thức mở rộng HtmlHelper<TModel>để giải quyết tên ràng buộc:

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);
        }
    }
}

người trợ giúp dao cạo của bạn sẽ giống như bình thường:

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

sau đó ở đây bạn có thể sử dụng nó

@TheHelper.MyComponent(Html.GetNameForBinding(x => x.MyProperty))

Đây không phải là những gì @ Html.IdFor (...) dành cho?
Alex Dresko

Có, bạn có thể làm với @Htm.IdFornhưng cần thêm quá trình để chuyển nó sang string ( .ToHtmlString()), nơi các helper đòi hỏi chuỗi
ktutnik
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.