Załóżmy, że mam widok wpisany do kolekcji, np. List<ItemViewModel>
:NameDo generowania niepoprawnej nazwy podczas iteracji nad kolekcją w szablonie edytora
@model List<ItemViewModel>
@for(int i = 0; i < Model.Count; i++)
{
@Html.EditorFor(m => m[i].Foo)
@Html.EditorFor(m => m[i].Bar)
}
Foo
i Bar
są po prostu właściwości smyczkowych.
Generuje to atrybuty nazwy HTML formularza [i].Foo
i [i].Bar
, które oczywiście są poprawne i wiążą się poprawnie po opublikowaniu w formularzu.
Załóżmy teraz, zamiast tego, że powyższe zdanie jest szablon edytor, który jest renderowany podobnie jak (gdzie Model.Items
jest List<ItemViewModel>
):
@model WrappingViewModel
@Html.EditorFor(m => m.Items)
Nagle, nazwy generowane wewnątrz szablonu edytora mają postać - na przykład - Items.[i].Foo
. Domyślny segregator modelu nie może tego powiązać, ponieważ oczekuje formy Items[i].Foo
.
Działa to dobrze w pierwszym scenariuszu - gdzie widok nie jest szablon redaktor - a także działa dobrze, gdzie zbiór jest nieruchomość, a nie całego modelu
@Html.EditorFor(m => m.Items[i].Foo)
zawiedzie, gdy tylko sam model to kolekcja i widok jest szablonem edytora.
Istnieje kilka sposobów pracy wokół tego, z których żadna nie jest idealna:
- Wpisz szablon redaktor indywidualnej instancji
ItemViewModel
- to nie jest dobre, jak rzeczywista szablon w pytaniu zawiera dodatkowe znaczniki do dodawania do/usuwania z kolekcji. Muszę umieć pracować z całą kolekcją wewnątrz szablonu. - Owiń w innej usłudze (np. Implementując
ItemListViewModel
) i przekaż ją do szablonu - to też nie jest idealne, ponieważ jest to aplikacja dla przedsiębiorstw, której nie chciałbym zaśmiecać zbytecznymi modelami widoku zwijania. - Generowanie znaczników dla wewnętrznych szablonów edytora ręcznie w celu uzyskania poprawnej nazwy - właśnie to robię, ale wolałbym tego uniknąć, ponieważ tracę elastyczność HtmlHelpers.
Więc pytanie: Dlaczego NameFor
(a więc EditorFor
) wykazują tego zachowania w tej konkretnej sytuacji, kiedy to działa dobrze dla drobnymi zmianami (to jest to zamierzone, a jeśli tak, to dlaczego)? Czy istnieje prosty sposób obejścia tego zachowania bez żadnych niedociągnięć powyższych?
Zgodnie z wnioskiem, aby odtworzyć pełny kod:
modele:
public class WrappingViewModel
{
[UIHint("_ItemView")]
public List<ItemViewModel> Items { get; set; }
public WrappingViewModel()
{
Items = new List<ItemViewModel>();
}
}
public class ItemViewModel
{
public string Foo { get; set; }
public string Bar { get; set; }
}
Controller działania:
public ActionResult Index()
{
var model = new WrappingViewModel();
model.Items.Add(new ItemViewModel { Foo = "Foo1", Bar = "Bar1" });
model.Items.Add(new ItemViewModel { Foo = "Foo2", Bar = "Bar2" });
return View(model);
}
Index.cshtml:
@model WrappingViewModel
@using (Html.BeginForm())
{
@Html.EditorFor(m => m.Items)
<input type="submit" value="Submit" />
}
_ItemView.cshtml (szablon redaktor):
@model List<ItemViewModel>
@for(int i = 0; i < Model.Count; i++)
{
@Html.EditorFor(m => m[i].Foo)
@Html.EditorFor(m => m[i].Bar)
}
Nazwa atrybuty Foo
i Bar
wejść będzie formie Model.[i].Property
i nie będą wiązać z powrotem, gdy pisał do sposobu działania z podpis ActionResult Index(WrappingViewModel)
. Zauważ, że, jak wspomniano powyżej, działa to dobrze, jeśli wykonasz iterację ponad Items
w widoku głównym lub, jeśli pozbędziesz się WrappingViewModel
, ustaw model najwyższego poziomu na List<ItemViewModel>
i wykonaj bezpośrednio iterację ponad . Nie udaje się tylko w tym konkretnym scenariuszu.
mógłbyś zaproponować kod źródłowy działania dla drugiego scenariusza?Jakie parametry oczekujesz w działaniu? –
@AlexanderSimonov Wezwę trochę kodu źródłowego do odtworzenia problemu nieco później. –
@AlexanderSimonov Pełny, powtarzalny kod, zgodnie z życzeniem. –