Razor View движок и модель в помощниках HTML - PullRequest
2 голосов
/ 13 февраля 2012

Я пытаюсь создать форму из такой модели:

class NewContractorModel
{
    //...
    public PhotoModel photos { get; set; }
    //...
}
class PhotoModel
{
    public List<Photo> f { get; set; }
}

Из контроллера я делаю некоторые манипуляции (на самом деле я удалил несколько фотографий из коллекции) на объекте модели и помещаю их на страницу просмотра, используя это:

return new View("SomeView", model);

Я пытался создать входные данные (скажем, скрытые входные) для каждой фотографии.

for (int i = 0; i < Model.photos.f.Count; ++i)
{
    @Html.HiddenFor(m => m.photos.f[i].Uri)
    @Html.HiddenFor(m => m.photos.f[i].ThumbnailUri)
    @Html.HiddenFor(m => m.photos.f[i].SmallThumbnailUri)
    @Html.TextBoxFor(m => m.photos.f[i].Description, new { placeholder = "Dodaj opis" })
}

Но, как я заметил, это не работает, потому что он отклоняет все модификации модели (он по-прежнему сохраняет все фотографии в списке, несмотря на то, что я удалил их в методе Controler).

Тогда я попробовал этот код:

for (int i = 0; i < Model.photos.f.Count; ++i)
{
    Photo photo = Model.photos.f[i];
    <input id="photos_f_@{@i}__Uri" name="photos.f[@{@i}].Uri" type="hidden" value="@photo.Uri"/>
    <input id="photos_f_@{@i}__ThumbnailUri" name="photos.f[@{@i}].ThumbnailUri" type="hidden" value="@photo.ThumbnailUri"/>
    <input id="photos_f_@{@i}__SmallThumbnailUri" name="photos.f[@{@i}].SmallThumbnailUri" type="hidden" value="@photo.SmallThumbnailUri"/>
    <input id="photos_f_@{@i}__Description" name="photos.f[@{@i}].Description" placeholder="Dodaj opis" type="text" value="@photo.Description"/>
}

... и на этот раз ЭТО РАБОТАЕТ!

Может кто-нибудь объяснить мне, в чем разница между этими двумя частями кода? Я пытался использовать этот код более десяти раз, и он всегда работает одинаково, поэтому я не виноват. ;) Я думаю, что есть ошибка в методах HtmlHelper, но есть ли обход? Я хотел бы использовать вспомогательные методы вместо необработанного HTML.

EDIT: Это упрощенный класс контроллера.

public class MyController
{
    private NewContractorModel _model = null;

    protected override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        _model = SerializationUtility.Deserialize(Request.Form["Data"]) as NewContractorModel;
        if (_model == null)
                 _model = TempData["Data"]  as NewContractorModel;
        if (_model == null)
                 _model = new NewContractorModel() as NewContractorModel;

        TryUpdateModel(_model);
    }

    protected override void OnResultExecuted(ResultExecutedContext filterContext)
    {
        if (filterContext.Result is RedirectToRouteResult)
            TempData["Data"] = _model;
    }

    private bool CheckModel(object model)
    {
        Type type = model.GetType();

        PropertyInfo[] properties = type.GetProperties();
        foreach (PropertyInfo p in properties)
        {
            object[] attr = p.GetCustomAttributes(true);
            foreach (object a in attr)
            {
                if (a is ValidationAttribute)
                {
                    object value = p.GetValue(model, null);
                    if (!((ValidationAttribute)a).IsValid(value))
                        return false;
                }
            }
        }
        return true;
    }

    protected ActionResult SelectPage(string delPhoto)
    {
        if (!CheckModel(_model))
        {
            // Do some action
        }
        //.....
        foreach (ZAY.Database.Photo p in _model.photos.f)
        {
            if (p.Uri == Request["delPhoto"])
            {
                _model.photos.f.Remove(p);
                break;
            }
        }
        //.....
        return View("SomeView", _model);
    }
}

Я заметил, что внутри лямбды модель выглядит так же, как после вызова TryUpdateModel (до внесения изменений). Если я не использую лямбды, модель модифицируется ...: /

А также мой класс Photo (сгенерированный из EntityFramework - так что ничего интересного), а также упрощенный:

public class Photo : EntityObject
{
    [Required]
    public string Uri { get; set; }

    [Required]
    public string ThumbnailUri { get; set; }

    [Required]
    public string SmallThumbnailUri { get; set; }

    public string Description { get; set; }
}

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

Ответы [ 2 ]

1 голос
/ 15 февраля 2012

Это ответ на мою проблему:

http://blogs.msdn.com/b/simonince/archive/2010/05/05/asp-net-mvc-s-html-helpers-render-the-wrong-value.aspx

Интересно, почему это не упоминается в документации ...: /

0 голосов
/ 13 февраля 2012

Из вашего описания я не совсем понимаю, что происходит в вашем первом примере. Но у вас наверняка есть проблема с областью действия переменной цикла i.

Поскольку выражение m => m.photos.f[i] включает замыкания, оно будет оценено позже, когда цикл for уже завершен. Выражение захватывает переменную i (а не значение переменной i). Когда он в конечном итоге оценивается, он находит значение Model.photos.f.Count в переменной i. Поэтому все скрытые поля и текстовые поля будут использовать одно и то же недопустимое значение i .

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

...