ASP MVC.NET - как связать KeyValuePair? - PullRequest
11 голосов
/ 19 августа 2009

Можно ли связать такого рода имущество?

public KeyValuePair<string, string> Stuff { get; set; }

Я пытался использовать следующий код в представлении, но он не работает:

<%=Html.Text("Stuff", Model.Stuff.Value)%>    
<%=Html.Hidden("Model.Stuff.Key", Model.Stuff.Key)%>

Ответы [ 4 ]

8 голосов
/ 19 августа 2009

KeyValuePair<K,V> - это структура, а не класс, поэтому каждый вызов вашего свойства Stuff возвращает копию оригинального KeyValuePair. Итак, когда вы связываетесь с Model.Stuff.Value и Model.Stuff.Key, вы на самом деле работаете с двумя различными экземплярами KeyValuePair<K,V>, ни один из которых не является тем из вашей модели. Поэтому, когда они обновляются, они не обновляют свойство Stuff в вашей модели ... QED

Кстати, свойства Key и Value доступны только для чтения, поэтому вы не можете их изменять: вам нужно заменить KeyValuePair экземпляр

Должен работать следующий обходной путь:

Модель:

private KeyValuePair<string, string> _stuff;
public KeyValuePair<string, string> Stuff
{
    get { return _stuff; }
    set { _stuff = value; }
}

public string StuffKey
{
    get { return _stuff.Key; }
    set { _stuff = new KeyValuePair<string, string>(value, _stuff.Value); }
}

public string StuffValue
{
    get { return _stuff.Value; }
    set { _stuff = new KeyValuePair<string, string>(_stuff.Key, value); }
}

Просмотр:

<%=Html.Text("Stuff", Model.StuffValue)%>    
<%=Html.Hidden("Model.StuffKey", Model.StuffKey)%>
0 голосов
/ 28 мая 2013

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

public class CustomModelBinder : DefaultModelBinder
{
    public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        var model = base.BindModel(controllerContext, bindingContext);            
        model = ResolveKeyValuePairs(bindingContext, model);
        return model;
    }

    private object ResolveKeyValuePairs(ModelBindingContext bindingContext, object model)
    {
        var type = bindingContext.ModelType;
        if (type.IsGenericType)
        {
            if (type.GetGenericTypeDefinition() == typeof (KeyValuePair<,>))
            {                    
                var values = bindingContext.ValueProvider as ValueProviderCollection;
                if (values != null)
                {
                    var key = values.GetValue(bindingContext.ModelName + ".Key");
                    var keyValue = Convert.ChangeType(key.AttemptedValue, bindingContext.ModelType.GetGenericArguments()[0]);
                    var value = values.GetValue(bindingContext.ModelName + ".Value");
                    var valueValue = Convert.ChangeType(value.AttemptedValue, bindingContext.ModelType.GetGenericArguments()[1]);
                    return Activator.CreateInstance(bindingContext.ModelType, new[] {keyValue, valueValue});
                }

            }
        }
        return model;
    }
0 голосов
/ 05 декабря 2012

Если вам нужно привязать словарь, чтобы каждое значение имело текстовое поле для его редактирования, ниже приведен один из способов заставить его работать. Действительно важными частями, которые влияют на то, как генерируется атрибут name в HTML, является выражение модели, которое обеспечивает связывание модели при обратной передаче. Этот пример работает только для словаря.

В связанной статье объясняется синтаксис HTML, который делает привязку работающей, но он оставляет синтаксис Razor для выполнения этой загадки. Кроме того, статья отличается тем, что позволяет редактировать как ключи, так и значения, и использует целочисленный индекс, хотя ключ словаря является строкой, а не целым числом. Поэтому, если вы пытаетесь связать словарь, вам действительно нужно сначала оценить, хотите ли вы, чтобы значения были редактируемыми, или и ключи, и значения, прежде чем вы решите, какой подход использовать, потому что эти сценарии совершенно разные. 1003 *

Если вам когда-либо понадобится привязать сложный объект, т. Е. Словарь, тогда вы просто должны иметь текстовое поле для каждого свойства с выражением, сверляющим свойство, как в статье.

http://www.hanselman.com/blog/ASPNETWireFormatForModelBindingToArraysListsCollectionsDictionaries.aspx

 public class SomeVM
    {
        public Dictionary<string, string> Fields { get; set; }
    }

    public class HomeController : Controller
    {
        [HttpGet]
        public ViewResult Edit()
        {
            SomeVM vm = new SomeVM
            {
             Fields = new Dictionary<string, string>() {
                    { "Name1", "Value1"},
                    { "Name2", "Value2"}
                }
            };

            return View(vm);

        }

        [HttpPost]
        public ViewResult Edit(SomeVM vm) //Posted values in vm.Fields
        {
            return View();
        }
    }

CSHTML:

Редакторы только для значений (конечно, вы можете добавить LabelFor для создания меток на основе ключа):

@model MvcApplication2.Controllers.SomeVM

@using (Html.BeginForm()) {
    @Html.ValidationSummary(true)

    <fieldset>
        <legend>SomeVM</legend>

        @foreach(var kvpair in Model.Fields)
        {
            @Html.EditorFor(m => m.Fields[kvpair.Key])  //html: <input name="Fields[Name1]" …this is how the model binder knows during the post that this textbox value gets stuffed in a dictionary named “Fields”, either a parameter named Fields or a property of a parameter(in this example vm.Fields).
        }

        <p>
            <input type="submit" value="Save" />
        </p>
    </fieldset>
}

Редактирование обоих ключей / значений: @ {var fields = Model.Fields.ToList (); }

    @for (int i = 0; i < fields.Count; ++i) 
    {
        //It is important that the variable is named fields, to match the property name in the Post method's viewmodel.
        @Html.TextBoxFor(m => fields[i].Key)
        @Html.TextBoxFor(m => fields[i].Value)

        //generates using integers, even though the dictionary doesn't use integer keys,
        //it allows model binder to correlate the textbox for the key with the value textbox:            
        //<input name="fields[0].Key" ...
        //<input name="fields[0].Value" ...

        //You could even use javascript to allow user to add additional pairs on the fly, so long as the [0] index is incremented properly
    }
0 голосов
/ 19 августа 2009
<%=Html.Text("Stuff.Value", Model.Stuff.Value)%>

Может работать?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...