.NET MVC 3 Razor Editor ile Html5 Yer Tutucular Uzantı için?


92

@ Html.EditorFor kullanarak Html5 yer tutucusunu yazmanın bir yolu var mı , yoksa yalnızca TextBoxFor uzantısını mı kullanmalıyım?

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

Ya da duyu belki (benzer DataAnnotations aracılığıyla 'Açıklama' ekran özelliğini kullanabilirsiniz kendi özel uzantı yazmak kılacak bu )?

Tabii o zaman aynı soru 'otomatik netleme' için de geçerli.

Yanıtlar:


68

Bir gelenek yazmak için aşağıdaki makaleye göz atabilirsiniz DataAnnotationsModelMetadataProvider.

Ve işte yeni tanıtılan IMetadataAware arabirimini içeren devam etmenin başka, daha fazla ASP.NET MVC 3ish yolu .

Bu arayüzü uygulayarak özel bir özellik oluşturarak başlayın:

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

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

Ve sonra modelinizi onunla süsleyin:

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

Daha sonra bir kontrolör tanımlayın:

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

Karşılık gelen bir görünüm:

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

Ve son olarak editör şablonu ( ~/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>

IMetadataAware arayüzü bilgisi (ve harika bir örnek) için teşekkürler!
seekay

4
bu hala MVC3 için geçerli mi? MVC3'te yeni bir [Ekran (Prompt = "buraya filigran yazın")] dikkatimi çekti, ancak çalışmasını sağlayamadım. Herhangi bir fikir?
smnbss

2
@smnbss Doğru söylüyorsunuz. Nasıl Promptçalışılacağını görmek için cevabıma bakın .
Daniel Liuzzi

6
vay bir yer tutucu yapmak için bu kadar çok iş? daha basit bir şey olmalı: S
krilovich

İşte, aşağıdaki cevaplardan bazılarına bakın. Pax'ta iyi bir tane var.
Termato

121

Darin Dimitrov'un cevabındaki smnbss yorumlarında Promptolduğu gibi, tam olarak bu amaç için mevcuttur, bu nedenle özel bir nitelik oluşturmaya gerek yoktur . Belgelerden:

Kullanıcı arabirimindeki istemler için filigranı ayarlamak için kullanılacak bir değer alır veya ayarlar.

Kullanmak için, görünüm modelinizin özelliğini şu şekilde dekore etmeniz yeterlidir:

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

Bu metin daha sonra uygun bir şekilde yerleştirilir ModelMetadata.Watermark. Kutunun dışında, MVC 3'teki varsayılan şablon Watermarközelliği yok sayar , ancak çalışmasını sağlamak gerçekten basittir. Tüm yapmanız gereken, MVC'ye onu nasıl işleyeceğini söylemek için varsayılan dize şablonunu ayarlamaktır. Darin'in yaptığı gibi String.cshtml dosyasını düzenleyin, tek fark filigranı ModelMetadata.AdditionalValuesalmak yerine doğrudan şunlardan alırsınız ModelMetadata.Watermark:

~ / Views / Shared / EditorTemplates / String.cshtml:

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

Ve işte bu.

Gördüğünüz gibi, her şeyin çalışmasını sağlamanın anahtarı placeholder = ViewData.ModelMetadata.Watermarkbirazdır.

Çok satırlı metin kutuları (metin alanları) için de filigran oluşturmayı etkinleştirmek istiyorsanız, MultilineText.cshtml için de aynısını yaparsınız:

~ / Views / Shared / EditorTemplates / MultilineText.cshtml:

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

6
@Brett var, gerçekten. EditorFor (), MVC 2'de tanıtılan şablonlu bir yardımcıdır. İlk bakışta TextBox () ile aynı şeyi yapıyor gibi görünebilir, ancak size HTML'nizin tam olarak nasıl oluşturulmasını istediğinizi kontrol etmenize olanak sağlama konusunda büyük bir avantaj sağlar. Cevabım, MVC'ye bu Promptöznitelikle ne yapılacağını "öğretmek" için bu özelliğe dayanmaktadır . Bu şablonlar hakkında daha fazla bilgi için, Brad Wilson'ın bu harika gönderisine bakabilirsiniz
Daniel Liuzzi

2
@DotNetWise Bunu neden söylediğinizden emin değilim; DisplayAttribute(Prompt dahil) tüm dize parametreleri yerelleştirilebilir. Sadece kendi ek açıklamada resourcetype belirtmek gerekir: [Display(ResourceType = typeof(PeopleResources), Prompt = "AgePrompt")]. Ve bu kadar. Filigran metin artık anahtar gelir AgeGroup kaynak içinde PeopleResources .
Daniel Liuzzi

1
Ya .resx kaynaklarını değil, i18N .po yerelleştirme sistemini kullanıyorsanız?
Adaptabi

3
@FrancisRodgers EditorTemplatesklasörü varsayılan olarak orada değildir; sadece Views\Sharedklasörünüzde oluşturursunuz (veya Views\{ControllerName}belirli bir denetleyiciye özel olmasını istiyorsanız). Daha sonra .cshtml şablonlarınızı bu klasöre yerleştirirsiniz ve gitmekte fayda var.
Daniel Liuzzi

2
@RobertIvanc Cevabı düzenledim ve sizin ve Ted'in bildirdiği sorunlara neden olan Raleigh Buckner tarafından yapılan düzenlemeyi geri aldım. Teşekkürler.
Daniel Liuzzi

22

Aslında çoğu zaman yer tutucu metin için görünen adı kullanmayı tercih ederim. Aşağıda, EkranAdı kullanımına bir örnek verilmiştir:

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

1
Bir filigran için özel bir veri açıklama İstemi vardır. Ve DisplayName alan etiketi içindir. Bunları karıştırmak kötü bir fikir. Doğru görevler için doğru şeyleri kullanın. Cevabıma bak.
Mike Eshva

1
teşekkürler, aradığım buydu, basit ve görünen adı alabildiğimiz noktaya o zaman neden daha fazla sınıf
ekleyelim

Bu, DisplayName tarafından sağlanan metinden çift kaçış sağlar - örneğin fransızca gibi aksanlı diller için iyi bir çözüm değildir.
marapet

3

Çok basit bir ders yazdım:

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

Kullanım şekli:

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

Ve bir görünüm modelindeki mülk:

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

Uyarı İstemi parametresi. Bu durumda, yerelleştirme için kaynaklardaki dizeleri kullanıyorum, ancak yalnızca dizeleri kullanabilirsiniz, yalnızca ResourceType parametresinden kaçının.


DisplayNameFor yöntemini derledim ve filigran için bir analog yaptı.
Mike Eshva

Merhaba, Display -> Prompt değeri belirtilmemişse, DisplayName öznitelik değerini kullanmak için MvcHtmlString WatermarkFor () yönteminizi değiştirebilir misiniz?
Sasa Tancev

WatermarkExtension sınıfınızı daha sonra açıkladığınız gibi kullanılabilmesi için nereye kaydedersiniz? Html.WatermarkFor (model => model.AddressSuffix)
Craig Gjerdingen

3

Bu yolu Kaynak dosyası ile kullanıyorum (artık İstem'e ihtiyacım yok!)

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

1

TextBoxFor ve PasswordFor için kullanılabilecek yukarıdaki fikirleri kullanarak yaptığım bir çözüm:

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

Bence özel bir EditorTemplate oluşturmanın iyi bir çözüm olmadığını düşünüyorum, çünkü farklı durumlar için birçok olası tablaya dikkat etmeniz gerekiyor: dizeler, numaralar, birleşik giriş kutuları vb. Diğer çözüm, HtmlHelper için özel uzantıdır.

Model:

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

Html yardımcı uzantısı:

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

}

Karşılık gelen bir görünüm:

@Html.BsEditorFor(x => x.Title)
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.