web-dev-qa-db-ja.com

なぜListBoxForはアイテムを選択しないのに、ListBoxは選択するのですか?

私の見解には次のコードがあります:

<%= Html.ListBoxFor(c => c.Project.Categories,
        new MultiSelectList(Model.Categories, "Id", "Name", new List<int> { 1, 2 }))%>

<%= Html.ListBox("MultiSelectList", 
        new MultiSelectList(Model.Categories, "Id", "Name", new List<int> { 1, 2 }))%>

唯一の違いは、最初のヘルパーが強く型付けされている(ListBoxFor)こと、そして選択された項目を表示できない(1,2)ですが、項目がリストに表示されている場合などです。より単純なListBox期待どおりに動作しています。

ここには明らかに何かが欠けています。私は2番目のアプローチを使用できますが、これは本当に私を悩ませているので、それを理解したいと思います。

参考までに、私のモデルは:

public class ProjectEditModel
{
    public Project Project { get; set; }
    public IEnumerable<Project> Projects { get; set; }
    public IEnumerable<Client> Clients { get; set; }
    public IEnumerable<Category> Categories { get; set; }
    public IEnumerable<Tag> Tags { get; set; }
    public ProjectSlide SelectedSlide { get; set; }
}

更新

ListBoxの名前をProject.Categories(モデルに一致)に変更したところ、アイテムの選択に失敗しました。

<%= Html.ListBox("Project.Categories",
        new MultiSelectList(Model.Categories, "Id", "Name", new List<int> { 1, 2 }))%>

私は明らかにここで起こっている魔法を理解していません。

アップデート2

わかりました、これは純粋に名前を付けています。たとえば、これは機能します...

<%= Html.ListBox("Project_Tags",
new MultiSelectList(Model.Tags, "Id", "Name", Model.Project.Tags.Select(t => t.Id)))%>

...フィールド名はProject.TagsではなくProject_Tagsであるため、実際には、TagsまたはProject.Tags以外のものが機能します。これがなぜ問題を引き起こすのか(エンティティ名と一致することを除いて)わかりません。また、これを調べて調べることができるほど十分ではありません。

30
Roger Rogers

私はこの問題に出くわしましたが、ついに問題が命名規則にあることに気付きました。

SelectListまたはMultiSelectListを含むViewBagまたはViewData popertyに、選択したアイテムを含むプロパティモデルと同じ名前を付けることはできません。少なくとも、ListBoxForまたはDropDownListForヘルパーを使用している場合はそうではありません。

次に例を示します。

    public class Person
    {
          public List<int> Cars { get; set; }
    }

    [HttpGet]
    public ActionResult Create()
    {
          //wont work
          ViewBag.Cars = new SelectList(carsList, "CarId", "Name"); 

          //will work due to different name than the property.
          ViewBag.CarsList = new SelectList(carsList, "CarId", "Name"); 

          return View();
    }

    //View
    @Html.ListBoxFor(model => model.Cars, ViewBag.CarsList as SelectList)

これを行う方法は他にもたくさんあると思いますが、私の問題は解決しました。誰かの役に立つことを願っています!

25
Olivier

私もこのまったく同じ問題に悩まされており、ListBoxとListBoxForで同じ問題が発生しました。

何をしても、ListBoxForで選択を行うことができません。 ListBoxに変更して、バインドしているデータのプロパティ名以外の名前を付けると、選択が発生します。

しかし、ListBoxForを使用しておらず、データがたとえばモデルクラス(Model.Departments)内にあるため、コントローラーに戻る途中でモデルバインディングが取得されず、プロパティがnullになります。

[〜#〜] edit [〜#〜]誰かが投稿した解決策をここに見つけました。 ListBoxForで値を選択する際の課題

3
Joshua Hayes

正解は、うまく機能しないことです。そのため、MVCコードを読み取りました。 IConvertibleを実装し、TypeConverterも作成する必要があります。

そのため、私のインスタンスでは、人々が国のリストから選択できるように、Countryクラスを用意しました。それを選択する喜びはありません。私は、オブジェクトがselectedItemslistitemsとの比較と等しいことを期待していましたが、そうではありません。 MultiListItemが機能し、選択されたアイテムを正しく取得するという事実にもかかわらず、モデルにバインドされた瞬間は、オブジェクトインスタンスの文字列表現が文字列"value"(または名前に一致するかどうかのチェックに基づいています)欠落している場合)SelectItemListのアイテムのリストで。

したがって、IConvertibleを実装し、ToStringの値と一致するSelectItemListから文字列値を返します。たとえば、私の場合、CountryCodeSelectItemValueプロパティにシリアル化されたため、ToString IConvertibleCountryCodeを返しました。これですべてが正しく選択されます。

TypeConverterが途中で使用されていることを指摘します。今回はその逆です。そのCountrycodeが戻ってきて、「EN」はCountryクラスインスタンスに変換する必要があります。そこがTypeConverterの出番です。また、このアプローチの使用がいかに難しいかを理解したのもこの頃です。

pS Categoryクラスでは、IConvertibleを実装する必要があります。私の会社のエンティティフレームワークからの場合は、部分クラスを使用してIConvertibleを実装し、ToStringを実装して、あなたが書いたTypeConverterで装飾する必要があります。 。

3
cineam mispelt

また、コントローラーでc.Project.CategoriesのModelStateをクリアしてみることもできます。

[HttpPost]
public ActionResult Index(ModelType model)
{
    ModelState.Remove("Project.Categories");
    return View("Index", model);
}

次の構文を使用します。

<%= Html.ListBoxFor(c => c.Project.Categories,
        new MultiSelectList(Model.Categories, "Id", "Name"))%>

ここで、c.Project.CategoriesはIEnumerable<int>

私の英語でごめんなさい。幸運を!

2
nika1218

これを試して

<%= Html.ListBoxFor(c => c.Project.Categories,
    new MultiSelectList(
        Model.Categories
        ,"Id"
        ,"Name"
        ,Model.Project.Tags.Select(
        x => new SelectListItem()
            {
            Selected = true,
            Text = x.TEXT,
            Value = x.ID.ToString()
            }).ToList())

       )
)%>
1
Alex

これは主な質問への回答ではありませんが、MVCが名前を生成すると、Project.TagsのようなものをProject_Tagsに変換し、ピリオドをアンダースコアに置き換えます。

これを行う理由は、要素IDのピリオドが、CSSへのタグのクラスを持つProjectという名前の要素のように見えるためです。明らかに悪いことなので、行動を予測可能に保つためにアンダースコアに変換します。

最初の例では、

<%= Html.ListBoxFor(c => c.Project.Categories,
    new MultiSelectList(Model.Categories, "Id", "Name", new List<int> { 1, 2 }))%>

リストボックスは、ページに提供されている厳密に型指定されたモデルのModel.Project.Categoriesにバインドしようとしています(ラムダ表記を使用)。 ListBoxForの2番目のパラメーターが何をしているのかわかりません。

ページに渡されるモデルは何ですか?

1
Alex White

Html.ListboxForとHtml.Listboxは、リストボックスをデータソースにバインドしない場合に適切に機能します。私は意図された使用がこれだと思います:

// Model
public class ListBoxEditModel
{
    public IEnumerable<Category> Categories { get; set; }
    public IEnumerable<Category> SelectedCategories { get; set; }
}    

ビューで:

@Html.ListBoxFor(m => m.SelectedCategories,
                 new MultiSelectList(Model.Categories, "Id", "Name"))
// or, equivalently
@Html.ListBox("SelectedCategories" ,
                 new MultiSelectList(Model.Categories, "Id", "Name"))

この場合、MultiSelectListで選択されている値を明示的に指定する必要がないことに注意してください。バインドするモデルが優先されます。

1
Alex