asp.net MVC複数選択ポストバック後の状態を覚えています
-
21-09-2019 - |
質問
私はasp.net MVCのアプリ、私があまりにも強く型付けされたのviewmodelsを使用しています。
上のエラーチェックのためのDataAnnotationsを使用しています私のエラーチェックが正常に動作して、フィールドが空白の場合は、エラーメッセージで戻って私の見解に掲示されます。しかし、私はエラーが発生した後、それの状態を覚えておく必要が私のフォーム上の複数選択/リストボックスは持っています。
現時点では、このような私のViewModelルックス(私は、関連するプロパティが含まれている):
public class ProfilePageViewModel : PageViewModel
{
public IList<FavouriteGenreViewModel> FavGenres { get; set; }
[Required(ErrorMessage = "*")]
public string SelectedGenres { get; set; }
public IDictionary<int, string> GenresList { get; set; }
}
これは私のコントローラの私の行動です。
public ActionResult Profile(ProfilePageViewModel viewModel)
{
if(!ModelState.IsValid)
{
viewModel.CountriesList = dropDownTasks.GetCountries();
viewModel.GendersList = dropDownTasks.GetGenders();
viewModel.GenresList = dropDownTasks.GetGenres();
viewModel.TimezonesList = dropDownTasks.GetTimezones();
viewModel.FavGenres =
return View(viewModel);
}
. . .
私の複数選択がGenresListでオプションを選択しFavouriteGenreViewModelのリストを受け取り、それがこのGETアクションでAutoMapperを使用しない、しかしobviousllyそれは私の投稿の値を忘れてしまうので、私はポストにAutoMapperを使用することはできません。
私は、しかし、私は、誰かがこれに対処するよりエレガントな方法を持って期待しています...、私掲示バック一度値を再使用することができ、そのようにIDの代わりにFavouriteGenreViewModelさんのリストの文字列delimmatedカンマを使用してについて考えています問題ます。
ありがとうございます!
ポール
解決
私は私の周りいくつか突っついた後自分の質問に答えることができると思います。
私のViewModelに私はそうのようなデータ型として文字列配列を使用します:
public class ProfilePageViewModel : PageViewModel
{
[Required(ErrorMessage = "*")]
public string[] FavGenres { get; set; }
public IDictionary<int, string> GenresList { get; set; }
}
私はFavGenresに選択した値を設定することができ、私の見解では、その後、私は場合には、あなたがここに不思議に思っている私のカスタムモデルバインダーがいっぱいである...再び有効なオブジェクトにカンマ区切り文字列を変換するためのカスタムモデルバインダーを持っています..ます。
public class AccountCustomModelBinder : DefaultModelBinder
{
private readonly IGenreRepository genreRepository;
private readonly ITimezoneRepository timeZoneRepository;
private readonly ICountryRepository countryRepository;
public AccountCustomModelBinder() : this(
ServiceLocator.Current.GetInstance<IGenreRepository>(),
ServiceLocator.Current.GetInstance<ITimezoneRepository>(),
ServiceLocator.Current.GetInstance<ICountryRepository>())
{
}
public AccountCustomModelBinder(IGenreRepository genreRepository, ITimezoneRepository timeZoneRepository,
ICountryRepository countryRepository)
{
Check.Require(genreRepository != null, "genreRepository is null");
Check.Require(timeZoneRepository != null, "timeZoneRepository is null");
Check.Require(countryRepository != null, "countryRepository is null");
this.genreRepository = genreRepository;
this.timeZoneRepository = timeZoneRepository;
this.countryRepository = countryRepository;
}
protected override void BindProperty(ControllerContext controllerContext, ModelBindingContext bindingContext, System.ComponentModel.PropertyDescriptor propertyDescriptor)
{
Account account = bindingContext.Model as Account;
if (account != null)
{
// gender
if (propertyDescriptor.Name == "Gender")
{
if (bindingContext.ValueProvider.ContainsKey("Gender"))
{
account.Gender = bindingContext.ValueProvider["Gender"].AttemptedValue.ToString();
return;
}
}
// TimezoneId
if (propertyDescriptor.Name == "TimezoneId")
{
if (bindingContext.ValueProvider.ContainsKey("TimezoneId")) {
account.Timezone = timeZoneRepository.FindOne(Convert.ToInt32(bindingContext.ValueProvider["TimezoneId"].AttemptedValue));
return;
}
}
// CountryId
if (propertyDescriptor.Name == "CountryId")
{
if (bindingContext.ValueProvider.ContainsKey("CountryId")) {
account.Country = countryRepository.FindOne(Convert.ToInt32(bindingContext.ValueProvider["CountryId"].AttemptedValue));
return;
}
}
// FavGenres
if (propertyDescriptor.Name == "FavGenres")
{
if (bindingContext.ValueProvider.ContainsKey("FavGenres")) {
// remove all existing entries so we can add our newly selected ones
account.ClearFavGenres();
string favIds = bindingContext.ValueProvider["FavGenres"].AttemptedValue;
foreach (string gId in favIds.Split(',')) {
account.AddFavGenre(genreRepository.Get(Convert.ToInt32(gId)));
}
return;
}
}
}
base.BindProperty(controllerContext, bindingContext, propertyDescriptor);
}
}