1

asp.net mvc アプリのエラー チェックに DataAnnotations を使用しています。厳密に型指定された ViewModel も使用しています。

エラー チェックは正常に機能しており、フィールドが空白の場合はエラー メッセージがビューに表示されます。ただし、フォームに MultiSelect / Listbox があり、エラー後の状態を覚えておく必要があります。

現時点では、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); 
        }

        . . .

私の MultiSelect は FavouriteGenreViewModel のリストを取得して GenresList のオプションを選択します。これは GET アクションで AutoMapper を使用して行いますが、投稿された値を忘れてしまうため、投稿で AutoMapper を使用できないことは明らかです。

FavouriteGenreViewModel のリストの代わりにコンマで区切られた ID の文字列を使用することを考えました。そうすれば、ポストバックされた値を再利用できます...しかし、誰かがこの問題に対処するよりエレガントな方法を持っていることを願っています。

ありがとうございました!

ポール

4

1 に答える 1

2

いくつか突っついた後、私は自分の質問に答えることができると思います。

私の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);
    }

}
于 2010-01-17T15:51:37.657 に答える