Sveiki,
neseniai pradėjau žiūrinėti ASP.NET MVC ir susidūriau su viena problema, nežinau, kaip ją čia gražiai išspręst.
View'e checkbox'ai sugeneruojami iš Model sąrašo (pvz Model.Users[]). Generuoju juos per foreach, pavadinu kiekvieną "chk"+i. Papostinus formą su tais checkbox'ais norėtusi, kad pažymėtų checkbox'ų pavadinimai būtų (kažkokiu būdu) priskirti atgal Model.Users[] per UpdateModel metodą. Ar yra koks būdas kaip tai būtų galima atlikti iškvietus tik UpdateModel() metodą? Ar reikės ieškoti savo checkbox'ų FormCollection sąraše, tai yra UpdateModel šiuo atveju teks pamiršt? Ar gal yra koks kitas būdas kaip postint čekboksų sarašus (mano atveju medžius)?
Ačiū :)
Sveikas,
Jeigu gerai supratau, realiai tau užteks savo checkbox elementams priskirti name='Users[0]', sekančiam - name='Users[1]' ir pan. Daugiau info - http://haacked.com/archive/2008/10/23/model-binding-to-a-list.aspx.
Tikiuosi padės ;)
taip, tai beveik veikia (uždėti interfeisą tik su get Name User klasei?). Vietoj interfeiso turi būti klasė, nes parametrai yra uždedami per Reflection'ą. Bet toks būdas man nelabai tinka, nes tenka koreguot dalykinę klasę.
Suradau, kad tokiais atvejais rekomenduoja naudotis IModelBinder. Padariau štai taip, nežinau ar korektiškai, bet veikia lyg gerai.
[ModelBinder(typeof(UserViewModelBinder))] class UsersViewModel
{ public string Title { get; set; } public User[] Users { get; set; } }
public class UserViewModelBinder : DefaultModelBinder { protected override void BindProperty(ControllerContext controllerContext, ModelBindingContext bindingContext, System.ComponentModel.PropertyDescriptor propertyDescriptor) { if (propertyDescriptor.DisplayName == "Users") { var model = (UserViewModel)bindingContext.Model; for (int i = 0; i < model.Users.Count; i++) { model.Users[i].IsChecked = (from v in bindingContext.ValueProvider where v.Key.StartsWith("Users[" + i + "]") select (string)v.Value.ConvertTo(typeof(string)) != "false") .SingleOrDefault(); } } else base.BindProperty(controllerContext, bindingContext, propertyDescriptor); } }
super! Kaip tik tai ko man reikėjo.
Bet pritaikęs tą metodą iškilo kita problema. Yra tokios klasės:
class UsersViewModel { public string Title { get; set; } public User[] Users { get; set; } }
User { public string Name { get; set; } public bool IsChecked { get; set; } }
puslapyje iš UsersViewModel.Users generuoju tų checkbox elementų sąrašą. Ir man reikia, kad bindintų ne visą User objektą o tiktai IsChecked parametrą. Bandau tai padaryti UpdateModel pateikiant bindinamų parametrų sąrašą, bet čia susiduriu su problema - šitas parametras yra pats parametro dalis, be to dar ir sąrašo.
[AcceptVerbs(HttpVerbs.Post)] public ActionResult Index(FormCollection formCollection) { UpdateModel(_usersViewModel, new string[] { "Title", "Users.IsChecked" /* tai nepraeina :( */ } ); return View(_usersViewModel); }
gal yra koks sprendimas čia? Pats nesugalvoju ir google nepadeda :)
Praktikoje nesu bandęs, bet teoriškai turėtų suveikti toks dalykas:
interface IUserUpdate { string Name { get; } bool IsCheked { get; set; } }
interface IUsersUpdate { string Title { get; set; } UpdateUser[] Users { get; set; } }
Ir tada:
[AcceptVerbs(HttpVerbs.Post)] public ActionResult Index(FormCollection formCollection) { UpdateModel<IUsersUpdate>(_usersViewModel); return View(_usersViewModel); }
Dar kartą, čia tik teoriniai pamąstymai...
Atrodo visai neblogas sprendimo variantas.