2017-01-11 5 views
0

Я проверил MVC post a list of complex objects, а также https://mhwelander.net/2014/03/26/asp-net-mvc-model-binding-not-occurring-when-posting-list-of-complex-types/ и еще несколько сообщений по этому вопросу.MVC 5 и список сложного типа

Я бы предпочел задать вопрос, чтобы понять, а не просто скопировать вставить ответ.

У меня есть сложный тип, как показано ниже:

public interface ICaracteristic 
{ 
    int value { get; set; } 
    int max { get; set; } 
    string name { get; set; } 
} 

public class BaseAttributes : ICaracteristic 
{ 
    public int max { get; set; } 
    public int value { get; set; } 
    public string name { get; set; } 
    Random r = new Random(); 
} 

и объект, используя список кратные этих типов:

public class Character 
{ 
    // Infos 
    public string characterName { get; set; } 
    public string playerName { get; set; } 
    public IGame game { get; set; } 
    // Caracteristics 
    public List<ICaracteristic> baseAttr { get; set; } 
    public List<ICaracteristic> skills { get; set; } 
    public List<ICaracteristic> stats { get; set; } 
    public List<ICaracteristic> spendPoints { get; set; } 
} 

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

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

Для редактирования я получаю символ в «моей БД» (на основе XML-листов, но это здесь не имеет значения), а также отображать его таким образом:

@model RPGmvc.Models.Character 
@using (Html.BeginForm()) 
{ 
@Html.AntiForgeryToken() 
    <h4>Character @Html.TextBoxFor(model => model.characterName)</h4> 
    <hr /> 
    @Html.ValidationSummary(true, "", new { @class = "text-danger" }) 

<div class="row"> 
    <!--SECTION BASE ATTRIBUTES--> 
    <div class="col-md-3"> 


     <!-- @foreach (var item in Model.baseAttr) 
     { 
      <div> 
       <label>@Html.DisplayFor(model => item.name)</label> 
       <p>@Html.EditorFor(model => item.value, new { @class = "form-control" })</p> 
      </div> 
     } 

Для отображения, это работает отлично: он показывает правильные имена и значения каждого базового атрибута моего символа (а также значения других списков).

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

Что странно, так это то, что он смешивает разные конструкторы этой модели: имя игрока, которое я не использую в моем шаблоне редактирования, имеет значение «toby defined» (как в моем пустом базовом конструкторе), но characterName является одним из текущего редактируемого символа вместо «нового символа» (как в указанном конструкторе)

Я попытался использовать for вместо foreach, полагая, что, возможно, индекс в списке поможет для передачи правильных значений; но поскольку я использую интерфейс, который дал ошибку «Не удалось создать экземпляр интерфейса».

Я пробовал с помощью специального редактора, но он создал ту же проблему, что и «foreach».

(Вот пользовательский редактор, на всякий случай:

@model RPGmvc.Models.Caracteristic.ICaracteristic 

<p> 
    @Html.DisplayFor(m => m.name) 
    @Html.DisplayFor(m => m.value) 
</p> 

Обратите внимание, что с помощью интерфейса в качестве модели не вызывает никаких проблем.)

Я понимаю, что я мог бы, видимо, добавить очень много аннотаций на моей странице, чтобы отсортировать это, но так как пользовательский редактор не работал и не использовал индекс с индексом, мне сначала хотелось бы объяснить, что происходит:

Что происходит с вставкой модели здесь? Мог ли я «заставить» его создать экземпляр реализации моего интерфейса, а не самого интерфейса? Почему HttpPost создает настраиваемый объект, смешивающий мои конструкторы?

Благодарим за помощь.


Edit: Стивен Muelcke помог мне, советуя, чтобы удалить интерфейсы из моей модели и с использованием реальных реализаций.Это почти сработало:

Теперь мой пост принимает правильные значения BaseAttributes, но имена этих имен «null». Это проблематично, так как мой Datas приходит из XML-листов, в которых я ищу этот путь:

foreach (ICaracteristic battr in myCharac.baseAttr) 
     { 
      var currentNode = myDoc.SelectSingleNode("/character_sheet/base_attributes/" + battr.name.Replace(" ", "_").ToLower()); 
      currentNode.InnerText = battr.value.ToString(); 
     } 

Который явно терпит неудачу, так как имя «нуль».

Я только сделал изменение от «foreach» до «for» в разделе «Базовые атрибуты». В этом разделе все имена имеют значение null. В других разделах значения не принимаются.

Любая идея?

+0

Вы не можете привязываться к intefaces ('DefaultModelBinder' не может инициализировать экземпляр интерфейса). И вам нужен цикл 'for' (или пользовательский' EditorTemplate') - цикл 'foreach' не будет работать - см. [Этот ответ] (http://stackoverflow.com/questions/30094047/html-table-to-ado -сетью-DataTable/30094943 # 30094943). Вы можете создать пользовательский 'ModelBinder' для работы с интерфейсами, но вам также нужно будет опубликовать значения, указывающие, какая конкретная реализация инициализируется –

+0

@StephenMuecke Итак, если я заменил« List baseAttr »в моей модели символов« Список baseAttr ", он должен работать? – DoctorPrisme

+0

Да, если вы используете цикл 'for' (или пользовательский' EditorTempate' для типа 'BaseAttributes' и в основном представлении используйте' @ Html.EditorFor (m => m.baseAttr) ' –

ответ

0

Так, так как Стивен Муеке не заботится о репутации:

--Вы не может моделировать привязку к интерфейсу.

- Вы не можете сделать foreach в списке, потому что для моделирования требуется индекс.

- Вам нужно «контролировать» сортировку по каждому значению, которое вы хотите использовать, поэтому для сложных типов вам нужен один даже на отображаемом имени.

Хорошим решением является создание цикла for, в котором вы включаете @ Html.Hiddenfor в дополнение к @ Html.DisplayFor, так что отображаемое имя не редактируется, но все еще имеет элемент управления. Для взаимодействия интерфейса и модели не требуется взаимодействие, единственное решение - использовать реализацию интерфейса. К сожалению.