Как добавить атрибуты подсказки в Business Objects в MVC и отобразить в представлении
Как я могу предоставить некоторую форму атрибута для моих бизнес-объектов в моем приложении ASP.Net MVC, чтобы я мог взять тексты справки в представлении и сделать их всплывающими подсказками, такими как:
<%= Html.TextBox("PostalCode", Model.PostalCode, new {
title = "Please enter your postal code." })%>
Я хочу иметь возможность получить значение title из моей ViewModel, которая будет брать текст из атрибута бизнес-объекта.
Таким образом, как я могу применить атрибуты / метаданные текста справки к моим бизнес-объектам?
4 ответа
Вот как я это сделал:
Создан новый атрибут следующим образом:
public class HelpPromptAttribute : Attribute { public HelpPromptAttribute(string text) { myproperty = text; } protected string myproperty; public string HelpTextKey { get { return myproperty; } set { myproperty = value; } } }
Добавлен атрибут к свойству объекта следующим образом:
[HelpPrompt("ProjectDescription")] [Required(ErrorMessageResourceName = "ProjectDescriptionRequired", ErrorMessageResourceType = typeof(EntityValidationMessages))] [StringLength(50, ErrorMessageResourceName = "ProjectDescriptionTooLong", ErrorMessageResourceType = typeof(EntityValidationMessages))] public string ProjectDescription { get; set; }
Добавлен метод расширения для сущностей следующим образом:
public static class EntityBOExtensions { public static string PropertyHelp(this object objectBO, string PropertyName) { Type type = objectBO.GetType(); foreach (PropertyInfo pInfo in type.GetProperties()) { if (string.Compare(pInfo.Name, PropertyName) == 0) { foreach (Attribute attr in Attribute.GetCustomAttributes(pInfo)) { if (attr.GetType() == typeof(HelpPromptAttribute)) { string key = ((HelpPromptAttribute)attr).HelpTextKey; if (!string.IsNullOrEmpty(key)) return EntityBOHelp.ResourceManager.GetString(key); } } } } return null; } }
Добавлен HtmlHelper (простой) следующим образом:
public static string LocalisedTextBoxWithHelp(this HtmlHelper helper, string name, object value, string helptext) { string textbox = helper.TextBox(name, value, new { helpprompt = helptext }); return textbox; }
И, наконец, использовал следующую разметку в представлении:
<%= Html.LocalisedTextBoxWithHelp("project.ProjectDescription", Model.ProjectDescription, Model.PropertyHelp("ProjectDescription"))%>
Это делает работу, хотя и нуждается в доработке.;)
Я не думаю, что есть способ сделать это прямо из коробки.
Однако вы могли бы создать общий класс "модель-значение", который инкапсулировал бы в нем эту информацию, таким образом, сохраняя ваше строго типизированное представление. то есть:
ModelValue<string> postalCode = new ModelValue<string>("poscode value", "Please enter your postal code.")
Затем вы можете создать классы вашей модели, чтобы они содержали свойства типа ModelValue.
Ваш код выше будет выглядеть примерно так:
<%= Html.TextBox("PostalCode", Model.PostalCode.Value, new { watermark = "Postal Code", title = Model.PostalCode.Title })%>
Недостатком этого является то, что я не думаю, что mvc будет выполнять автоматическое связывание для вас, поэтому вам придется делать все сопоставления в представлении самостоятельно, как в этом примере, но также и в Post, который вам придется делать ручная привязка, если вы еще этого не сделали. Вы, вероятно, также создадите все свои свойства ModelValue в конструкторе модели и извлечете все значения заголовков из того места, где они хранятся, потому что вы не будете связывать их в Post (я думаю об ошибках проверки, приводящих к тому, что форма будет перерисована).
Если бы вы были очень заинтересованы, вы бы добавили атрибуты в свойства вашей модели, а затем каким-то образом проанализировали их при рендеринге страницы, но я понятия не имею, с чего начать, если вы хотите пойти по этому пути.
Я знаю, что это старо, но я недавно столкнулся с этой проблемой в проекте ASP.NET MVC3 и реализовал решение.
1. Создайте пользовательский атрибут для хранения текста справки.
public class HelpTextAttribute : DescriptionAttribute
{
public HelpTextAttribute(string helpText)
: base(helpText)
{ }
}
2. Создайте метод расширения HtmlHelper для получения значения атрибута.
public static class HtmlHelperExtensions
{
public static string HelpTextFor<TModel, TValue>(this HtmlHelper<TModel> html, Expression<Func<TModel, TValue>> expression)
{
var memberExpression = expression.Body as MemberExpression;
if (memberExpression == null)
throw new InvalidOperationException("Expression must be a member expression");
var attributes = memberExpression.Member.GetCustomAttributes(typeof(HelpTextAttribute), true);
var attribute = attributes.Length > 0 ? attributes[0] as HelpTextAttribute : null;
return html.Encode(attribute == null ? string.Empty : attribute.Description);
}
}
3. Аннотируйте свойство модели с помощью атрибута HelpText.
[HelpText("A level from which to start")]
[Required("You must select a level")]
public int Level { get; set; }
4. Просто используйте новый метод расширения HtmlHelper с вашим представлением
<div class="editor-help">
<%: Html.HelpTextFor(model => model.Level) %>
</div>
Обновить:
Вы можете просто создать новое свойство класса для каждого объекта с именем "Заголовок" или "Подсказка" и добавить к ним соответствующее строковое значение. Затем получите это свойство с MyObject. Title
Интересный вопрос. Я хотел бы увидеть ответ на это с помощью атрибутов, но вот два метода, которые я могу придумать:
Добавьте метод расширения к вашим объектам. Для этого потребуется много повторяющегося кода.
public static string GetTitle(this YourObject obj)
{
return "Title for object";
}
Html Helper метод расширения
Вы должны хранить заголовки объектов в этом вспомогательном методе.
public static string GetObjectTitle(this HtmlHelper html, string type)
{
switch(type)
{
case "Object1":
return "Title for object 1";
break;
case "Object2":
return "Title for object 2";
break;
default:
return "No titled specified for this object type";
break;
}
}
Чтобы вызвать этот метод:
<%= Html.GetObjectTitle(Model.GetType()) %>
Или в вашем примере:
<%= Html.TextBox("PostalCode", Model.PostalCode, new {
watermark = "Postal Code",
title = Html.GetObjectTitle(Model.GetType()) })%>
Я предпочитаю второй способ, потому что у вас есть место для хранения всех заголовков, и вам нужно будет писать меньше кода.
Тем не менее, я думаю, что добавление атрибута в класс и создание средства для получения этого атрибута будет работать немного лучше.