Реализация универсального атрибута dropdownlist и шаблонов решения


Моя цель, чтобы быть в состоянии оказать мой взгляд модели с помощью стандартного объекта.cshtml по редактор и шаблон отображения. Для этого мне нужно, чтобы иметь возможность всегда позвонить в HTML.Редактор(имясвойства) или в формате HTML.Дисплей(имясвойства) для того, чтобы сделать HTML-элемента.

Там было много ресурсов для создания пользовательских атрибутов и пользовательских шаблонов редактора. Однако я уперся в стену при создании DropDownListAttribute и шаблон, так как мне необходимо получить значения для списке выбора, а также установить выбранный элемент на основе текущего экземпляра модели представления.

Вот ссылка , я использовал, чтобы создать пользовательский ModelMetadataProvider и пользовательские атрибуты.

Вот проблема я столкнулся с получения текущего экземпляра модели представления.

Получается с помощью отражения здесь получить доступ к модели представления не безопасно. В зависимости от способа перебора свойств метаданных модели представления иногда могут быть null.

Вот моя реализация с использованием ресурсов, указанных выше. Это простая версия, которая использует только список для dropdownlist для. Используя этот пример было бы тривиально, чтобы использовать словари и набор текст-значение свойства:

Вид Модели:

public class PhoneNumberViewModel
{
    // ... normal properties and attributes
    [DropDownList("ContactTypes")]  // <-- This is the important one!
    public string ContactType { get; set; }
    public static IEnumerable<string> ContactTypes
    {
        get
        {
            return new List<string>()
            {
                "Home", "Work", "Mobile"
            }
        }
    }
}

Реализация DropDownListAttribute

public class DropDownListAttribute : MetadataAttribute
{
    private string _items;

    public DropDownListAttribute(string items)
    {
        _items = items;
    }

    public override void Process(System.Web.Mvc.ModelMetadata modelMetaData)
    {
        modelMetaData.AdditionalValues.Add("Items", _items);
        modelMetaData.TemplateHint = TemplateHints.DropDownList; // Just a const string
    }
}

Пользовательский HTML-Хелпер используется для отображения элементов, которые должны иметь доступ к экземпляр модели представления

@Html.ContextualEditor(propertyName)

Помощник ContextualEditor применения HTML

public static MvcHtmlString ContextualEditor(this HtmlHelper html, string expression)
{
    var model = html.ViewData.Model;
    var propertyMetadata = html.ViewData.ModelMetadata.Properties.Where(x => x.PropertyName == expression).Single();
    switch (propertyMetadata.TemplateHint)
    {
        case TemplateHints.DropDownList:
            var items = (IEnumerable<string>)model.GetType().GetProperty((string)propertyMetadata.AdditionalValues["Items"]).GetValue(model, null);
            var selectedValue = (string)model.GetType().GetProperty(expression).GetValue(model, null);
            var selectList = new TagBuilder("select");
            selectList.MergeAttribute("id", expression);
            selectList.MergeAttribute("name", expression);
            var options = new StringBuilder();
            foreach (var item in items)
            {
                var option = new TagBuilder("option");
                option.InnerHtml = item;
                if (item == selectedValue)
                    option.MergeAttribute("selected", "selected");
                options.Append(option.ToString());
            }
            selectList.InnerHtml = options.ToString();
            return MvcHtmlString.Create(selectList.ToString());
        default:
            return System.Web.Mvc.Html.EditorExtensions.Editor(html, expression);
    }
}

Пожалуйста, дайте мне знать, что вы думаете о реализации. Мне было бы интересно знать, если кто нашел более элегантный способ достижения этого результата.



4103
11
задан 18 сентября 2011 в 06:09 Источник Поделиться
Комментарии
1 ответ

Почему бы просто не сделать это?

public class PhoneNumberViewModel
{
// ... normal properties and attributes
[DropDownList("ContactTypes")] // <-- This is the important one!
public string ContactType { get; set; }

public static IEnumerable<SelectListItem> ContactTypes
{
get { return new[] { "Home", "Work", "Mobile" }.ToSelectList(); }
}
}

public static class ExtensionsForSelectListItem
{
public static IEnumerable<SelectListItem> ToSelectList(this IEnumerable<string> items)
{
return items.Select(x => new SelectListItem { Value = x });
}

public static MvcHtmlString ContextualEditor(this HtmlHelper html, string expression)
{

var model = html.ViewData.Model;

var propertyMetadata = ModelMetadata.FromStringExpression(expression, html.ViewData);

switch (propertyMetadata.TemplateHint)
{
case TemplateHints.DropDownList:
var items = (IEnumerable<SelectListItem>)model.GetType().GetProperty((string)propertyMetadata.AdditionalValues["Items"]).GetValue(model, null);
return html.DropDownList(expression, items);
default:
return System.Web.Mvc.Html.EditorExtensions.Editor(html, expression);
}
}

}

Я не тестировал этот код, чтобы получить товары. Но я предполагаю, что у вас эта часть рабочая.

Я также написал свою собственную вспомогательную библиотеку HTML, если вы хотите проверить некоторые другие примеры.

https://bitbucket.org/grcodemonkey/buildmvc

3
ответ дан 8 сентября 2012 в 01:09 Источник Поделиться