Как правильно редактировать два значения с помощью одного раскрывающегося списка ASP .NET MVC? - PullRequest
2 голосов
/ 03 июня 2011

Запись однозначно идентифицируется по Kind и RecordId.

У меня есть набор записей, которые я хочу отобразить в виде раскрывающегося списка, и при отправке я хотел бы получить SelectedKind и SelectedRecordId для дальнейшей обработки.

Проблема заключается в том, что, Я хочу, чтобы эти значения обрабатывались отдельно, но должен быть только один выпадающий список .
Каков наилучший способ сделать это?

Мои предложения:

Вариант 1

Заполните раскрывающийся список строками, такими как "Kind_RecordId", и установите обработчик JavaScript change, который будет анализировать строку и устанавливать значения скрытых полей.

Однако мне не очень нравится идея иметь логику строковых операций в разных местах (в контроллере при заполнении выпадающего списка и в представлении при разборе значений).Должен ли я перевести SelectItem заполнение логики также в представление и оставить вместо этого свои бизнес-объекты в модели представления?

Это также дает мне сообщение о том, что в редких случаях, когда JavaScript отключен, пользователь не сможетвообще добавьте форму.

Вариант 2

Предоставьте уникальное "Kind_RecordId" -подобное строковое свойство в моей модели формы и позвольте модели проанализировать его (или заполнить) черезсвойства доступа со строгим типом для контроллера?

Это кажется лучшим способом, но я не совсем уверен.Что я считаю хорошим в этом, так это то, что он будет сохранять всю логику синтаксического анализа / объединения в модели представления, и он не потерпит неудачу, когда JavaScript недоступен.

Мысли сообщества очень приветствуются.

Ответы [ 2 ]

2 голосов
/ 03 июня 2011

Элегантный способ сделать это - создать собственную модель подшивки и отдельный класс для хранения Kind и RecordId в качестве свойств .Вам нужно будет указать связующий элемент модели для вашего класса с атрибутом, и тогда вы сможете использовать класс в качестве параметра метода действия.

[ModelBinder (typeof (RecordIdentityBinder))]
public class RecordIdentity
{
    // Your types may be different
    public RecordKind Kind { get; set; }
    public int RecordId { get; set; }

    //TODO: replace this with your formatting algorithm
    public override string ToString ()
    {
        return string.Format ("{0}_{1}", Kind, RecordId);
    }

    //TODO: replace this with your parsing algorithm
    public static RecordIdentity Parse (string s)
    {
        string[] fragments = s.Split('_');

        if (fragments.Length != 2)
            return null;

        // Your object creation may be different
        return new MessagePartyIdentity {
            Kind = (RecordKind) Enum.Parse (typeof (RecordKind), fragments [0]),
            PartyID = int.Parse (fragments [1])
        };

    }
}

public class RecordIdentityBinder : IModelBinder
{
    public object BindModel (ControllerContext controllerContext, ModelBindingContext bindingContext)
    {            
        string key = bindingContext.ModelName;
        ValueProviderResult value = bindingContext.ValueProvider.GetValue (key);

        if (value == null || string.IsNullOrEmpty (value.AttemptedValue))
            return null;

        return RecordIdentity.Parse (value.AttemptedValue);
    }
}

public class MyController : Controller
{
    // ?identity=Foo_42 will become RecordIdentity { Kind = RecordKind.Foo, RecordId = 42 }
    public ActionResult DoSomethingWith (RecordIdentity selectedIdentity)
    {
        // ...
    }
}

В коде шаблона представления вы будетенеобходимо вызвать Html.DropDownListFor() со своим составным свойством :

@Html.DropDownListFor(m => m.SelectedIdentity, Model.RowList)

Для каждого значения в RowList или любого другого источника данных, который вы называете, убедитесь, что SelectListItem 'Свойство s Value установлено для класса ToString() output.

Имя свойства RecordIdentity -типа объекта, указанного в Html.DropDownListFor, должно соответствовать имени параметра действия.В противном случае вам нужно будет указать раскрывающееся имя в атрибуте Bind Prefix, как показано здесь :

public ActionResult DoSomethingWith ([Bind(Prefix="SelectedIdentity")] RecordIdentity identity)
{
    // do something you need
}

Также обратите вниманиечто он также будет работать, если вы хотите, чтобы RecordIdentity было свойством модели формы или любого класса, который вы хотели бы принять в качестве параметра для вашего метода действия. Связыватель будет вызываться в любом случае.

Следуя этому подходу, вы возлагаете ответственность за форматирование и анализ на один класс, который в значительной степени невидим и обеспечивает абстракцию над действительными полями .Однако я должен отметить, что такая проблема также может быть вызвана плохой организацией базы данных или организаций.Возможно, лучшим решением было бы снабдить каждый из перечисленных вами предметов собственным уникальным собственным ключом.

1 голос
/ 03 июня 2011

Я думаю, что лучше всего определить новый класс с 2 свойствами.Что-то похожее на:

public class KindRecordItem {
    public int Id {get; set;}
    public string Kind {get; set;}
    public int RecordId {get; set;}
    public string Text {get; set;}
}

Вы генерируете все допустимые / допустимые комбинации вида и recordId в коллекции, передаете эту коллекцию в представление и отображаете отображаемый текст в раскрывающемся списке.

<%= Html.DropDownListFor(m => m.SelectedKindRecordItem, 
        new SelectList(Model.KindRecordItems, "Id", "Text"),
        new SelectListItem { Value = "0", Text = "Please select an option" }) %>

В вашем контроллере SelectedKindRecordItem будет уникальным идентификатором, который вы можете найти, чтобы найти Kind и RecordId для обработки.

Id может быть сгенерирован как хеш Kind и RecordId или любым другим методом, чтобы сделать его уникальным.

...