Phần giữ chỗ Html5 với .NET MVC 3 Razor EditorĐể biết tiện ích mở rộng?


92

Có cách nào để viết trình giữ chỗ Html5 bằng @ Html.EditorFor không, hay tôi chỉ nên sử dụng phần mở rộng TextBoxFor tức là

@Html.TextBoxFor(model => model.Title, new { @placeholder = "Enter title here"})

Hoặc sẽ có ý nghĩa khi viết tiện ích mở rộng tùy chỉnh của riêng chúng tôi có thể sử dụng thuộc tính hiển thị 'Mô tả' thông qua DataAnnotations (tương tự như thế này )?

Tất nhiên, câu hỏi tương tự cũng áp dụng cho 'tự động lấy nét'.

Câu trả lời:


68

Bạn có thể xem qua bài viết sau để viết một tùy chỉnh DataAnnotationsModelMetadataProvider.

Và đây là một cách ASP.NET MVC 3ish khác để tiến hành liên quan đến giao diện IMetadataAware mới được giới thiệu .

Bắt đầu bằng cách tạo một thuộc tính tùy chỉnh triển khai giao diện này:

public class PlaceHolderAttribute : Attribute, IMetadataAware
{
    private readonly string _placeholder;
    public PlaceHolderAttribute(string placeholder)
    {
        _placeholder = placeholder;
    }

    public void OnMetadataCreated(ModelMetadata metadata)
    {
        metadata.AdditionalValues["placeholder"] = _placeholder;
    }
}

Và sau đó trang trí mô hình của bạn với nó:

public class MyViewModel
{
    [PlaceHolder("Enter title here")]
    public string Title { get; set; }
}

Tiếp theo xác định một bộ điều khiển:

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

Một chế độ xem tương ứng:

@model MyViewModel
@using (Html.BeginForm())
{
    @Html.EditorFor(x => x.Title)
    <input type="submit" value="OK" />
}

Và cuối cùng là mẫu trình soạn thảo ( ~/Views/Shared/EditorTemplates/string.cshtml):

@{
    var placeholder = string.Empty;
    if (ViewData.ModelMetadata.AdditionalValues.ContainsKey("placeholder"))
    {
        placeholder = ViewData.ModelMetadata.AdditionalValues["placeholder"] as string;
    }
}
<span>
    @Html.Label(ViewData.ModelMetadata.PropertyName)
    @Html.TextBox("", ViewData.TemplateInfo.FormattedModelValue, new { placeholder = placeholder })
</span>

cảm ơn vì thông tin (và một ví dụ tuyệt vời) về giao diện IMetadataAware!
seekay

4
điều này có còn hợp lệ cho MVC3 không? Tôi nhận thấy một [Display (Prompt = "type watermark here")] mới trong MVC3 nhưng không thể làm cho nó hoạt động. bất kỳ ý tưởng?
smnbss

2
@smnbss Bạn nói đúng. Hãy xem câu trả lời của tôi để biết cách thực hiện Prompt.
Daniel Liuzzi

6
wow nhiều công việc để thực hiện một trình giữ chỗ? phải là một cái gì đó đơn giản hơn: S
krilovich

Có, hãy xem một số câu trả lời dưới đây. Pax có một cái hay.
Termato

121

Như nhận xét của smnbss trong câu trả lời của Darin Dimitrov, Prompttồn tại cho chính xác mục đích này, vì vậy không cần tạo thuộc tính tùy chỉnh . Từ tài liệu:

Nhận hoặc đặt một giá trị sẽ được sử dụng để đặt hình mờ cho lời nhắc trong giao diện người dùng.

Để sử dụng nó, chỉ cần trang trí thuộc tính của mô hình xem của bạn như sau:

[Display(Prompt = "numbers only")]
public int Age { get; set; }

Văn bản này sau đó được đặt một cách thuận tiện ModelMetadata.Watermark. Ngoài ra, mẫu mặc định trong MVC 3 bỏ qua thuộc Watermarktính, nhưng làm cho nó hoạt động thực sự đơn giản. Tất cả những gì bạn cần làm là tinh chỉnh mẫu chuỗi mặc định, để cho MVC biết cách hiển thị nó. Chỉ cần chỉnh sửa String.cshtml, giống như Darin, ngoại trừ việc thay vì lấy hình mờ từ đó ModelMetadata.AdditionalValues, bạn sẽ có được nó ngay từ ModelMetadata.Watermark:

~ / Lượt xem / Đã chia sẻ / EditorTemplates / String.cshtml:

@Html.TextBox("", ViewData.TemplateInfo.FormattedModelValue, new { @class = "text-box single-line", placeholder = ViewData.ModelMetadata.Watermark })

Và đó là nó.

Như bạn có thể thấy, chìa khóa để làm cho mọi thứ hoạt động chính là placeholder = ViewData.ModelMetadata.Watermarkbit.

Nếu bạn cũng muốn bật tính năng đánh dấu nước cho các hộp văn bản nhiều dòng (textareas), bạn làm tương tự cho MultilineText.cshtml:

~ / Lượt xem / Chia sẻ / EditorTemplates / MultilineText.cshtml:

@Html.TextArea("", ViewData.TemplateInfo.FormattedModelValue.ToString(), 0, 0, new { @class = "text-box multi-line", placeholder = ViewData.ModelMetadata.Watermark })

6
@Brett Đúng vậy. EditorFor () là một trình trợ giúp tạo khuôn mẫu được giới thiệu trong MVC 2. Thoạt nhìn, nó có vẻ hoạt động tương tự như TextBox (), nhưng nó mang lại cho bạn lợi thế lớn là cho phép bạn kiểm soát chính xác cách bạn muốn tạo HTML của mình. Câu trả lời của tôi là dựa trên tính năng này để "dạy" MVC phải làm gì với Promptthuộc tính. Để biết thêm thông tin về những mẫu này, bạn có thể tham khảo bài viết tuyệt vời này bởi Brad Wilson: bradwilson.typepad.com/blog/2009/10/...
Daniel Liuzzi

2
@DotNetWise Tôi không chắc tại sao bạn lại nói như vậy; tất cả các tham số chuỗi của DisplayAttribute(bao gồm cả Lời nhắc) đều có thể bản địa hóa. Bạn chỉ cần phải xác định ResourceType trong chú thích của mình: [Display(ResourceType = typeof(PeopleResources), Prompt = "AgePrompt")]. Và đó là nó. Watermark văn bản hiện nay xuất phát từ chính AgeGroup trong nguồn PeopleResources .
Daniel Liuzzi

1
Điều gì sẽ xảy ra nếu bạn không sử dụng tài nguyên .resx mà không sử dụng hệ thống bản địa hóa i18N .po?
Adaptabi

3
EditorTemplatesThư mục @FrancisRodgers không có ở đó theo mặc định; bạn chỉ cần tạo trong Views\Sharedthư mục của mình (hoặc Views\{ControllerName}nếu bạn muốn nó dành riêng cho một bộ điều khiển nhất định). Sau đó, bạn đặt bạn đặt các mẫu .cshtml của mình bên trong thư mục này và bạn nên thực hiện.
Daniel Liuzzi

2
@RobertIvanc Tôi đã chỉnh sửa câu trả lời và hoàn nguyên bản chỉnh sửa do Raleigh Buckner thực hiện gây ra sự cố mà bạn và Ted đã báo cáo. Cảm ơn.
Daniel Liuzzi

22

Tôi thực sự thích sử dụng tên hiển thị cho phần lớn văn bản giữ chỗ. Đây là một ví dụ về việc sử dụng DisplayName:

  @Html.TextBoxFor(x => x.FirstName, true, null, new { @class = "form-control", placeholder = Html.DisplayNameFor(x => x.FirstName) })

1
Có một chú thích dữ liệu đặc biệt Nhắc nhở cho một hình mờ. Và DisplayName dành cho nhãn trường. Trộn chúng là một ý tưởng tồi. Sử dụng những thứ phù hợp cho những nhiệm vụ phù hợp. Nhìn vào câu trả lời của tôi.
Mike Eshva

1
cảm ơn, đó là những gì tôi đang tìm kiếm, đơn giản và đến điểm khi chúng ta có thể có được tên hiển thị thì tại sao thêm lớp
saqibahmad

Thao tác này sẽ thoát kép văn bản do DisplayName cung cấp - không phải là một giải pháp tốt, chẳng hạn như các ngôn ngữ có dấu như tiếng Pháp.
marapet

3

Tôi đã viết một lớp đơn giản như vậy:

public static class WatermarkExtension
{
    public static MvcHtmlString WatermarkFor<TModel, TValue>(this HtmlHelper<TModel> html, Expression<Func<TModel, TValue>> expression)
    {
        var watermark = ModelMetadata.FromLambdaExpression(expression, html.ViewData).Watermark;
        var htmlEncoded = HttpUtility.HtmlEncode(watermark);
        return new MvcHtmlString(htmlEncoded);
    }
}

Việc sử dụng như vậy:

@Html.TextBoxFor(model => model.AddressSuffix, new {placeholder = Html.WatermarkFor(model => model.AddressSuffix)})

Và thuộc tính trong một mô hình xem:

[Display(ResourceType = typeof (Resources), Name = "AddressSuffixLabel", Prompt = "AddressSuffixPlaceholder")]
public string AddressSuffix
{
    get { return _album.AddressSuffix; }
    set { _album.AddressSuffix = value; }
}

Thông báo tham số Nhắc. Trong trường hợp này, tôi sử dụng chuỗi từ tài nguyên để bản địa hóa nhưng bạn có thể chỉ sử dụng chuỗi, chỉ cần tránh tham số ResourceType.


Chỉ cần dịch ngược phương thức DisplayNameFor và tạo một tương tự cho hình mờ.
Mike Eshva

Xin chào, bạn có thể vui lòng thay đổi phương thức MvcHtmlString WatermarkFor () của mình để sử dụng giá trị thuộc tính DisplayName nếu giá trị Display -> Prompt không được chỉ định không?
Sasa Tancev

Bạn lưu lớp WatermarkExtension ở đâu để sau đó có thể sử dụng nó như bạn đã mô tả? Html.WatermarkFor (mô hình => model.AddressSuffix)
Craig Gjerdingen

3

Tôi sử dụng cách này với tệp Tài nguyên (không cần Lời nhắc nữa!)

@Html.TextBoxFor(m => m.Name, new 
{
     @class = "form-control",
     placeholder = @Html.DisplayName(@Resource.PleaseTypeName),
     autofocus = "autofocus",
     required = "required"
})

1

Đây là một giải pháp tôi đã thực hiện bằng cách sử dụng các ý tưởng trên có thể được sử dụng cho TextBoxFor và PasswordFor:

public static class HtmlHelperEx
{
    public static MvcHtmlString TextBoxWithPlaceholderFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper,
        Expression<Func<TModel, TProperty>> expression, object htmlAttributes)
    {
        var metadata = ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData);
        return htmlHelper.TextBoxFor(expression, htmlAttributes.AddAttribute("placeholder", metadata.Watermark));

    }

    public static MvcHtmlString PasswordWithPlaceholderFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper,
        Expression<Func<TModel, TProperty>> expression, object htmlAttributes)
    {
        var metadata = ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData);
        return htmlHelper.PasswordFor(expression, htmlAttributes.AddAttribute("placeholder", metadata.Watermark));

    }
}

public static class HtmlAttributesHelper
{
    public static IDictionary<string, object> AddAttribute(this object htmlAttributes, string name, object value)
    {
        var dictionary = htmlAttributes == null ? new Dictionary<string, object>() : htmlAttributes.ToDictionary();
        if (!String.IsNullOrWhiteSpace(name) && value != null && !String.IsNullOrWhiteSpace(value.ToString()))
            dictionary.Add(name, value);
        return dictionary;
    }

    public static IDictionary<string, object> ToDictionary(this object obj)
    {
        return TypeDescriptor.GetProperties(obj)
            .Cast<PropertyDescriptor>()
            .ToDictionary(property => property.Name, property => property.GetValue(obj));
    }
}

0

Tôi nghĩ rằng việc tạo một EditorTemplate tùy chỉnh không phải là giải pháp tốt, vì bạn cần quan tâm đến nhiều tepmlate có thể có cho các trường hợp khác nhau: chuỗi, numsers, combobox, v.v. Giải pháp khác là mở rộng tùy chỉnh cho HtmlHelper.

Mô hình:

public class MyViewModel
{
    [PlaceHolder("Enter title here")]
    public string Title { get; set; }
}

Tiện ích mở rộng trình trợ giúp html:

   public static MvcHtmlString BsEditorFor<TModel, TValue>(this HtmlHelper<TModel> htmlHelper,
    Expression<Func<TModel, TValue>> expression, string htmlClass = "")
{
    var modelMetadata = ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData);
    var metadata = modelMetadata;

    var viewData = new
    {
        HtmlAttributes = new
            {
                @class = htmlClass,
                placeholder = metadata.Watermark,
            }
    };
    return htmlHelper.EditorFor(expression, viewData);

}

Một chế độ xem tương ứng:

@Html.BsEditorFor(x => x.Title)
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.