7

私のモデルは次のとおりです。

public class testCreateModel
{
    public string s1 { get; set; }
    public SelectList DL { get; set; }

    public testCreateModel()
    {
        Dictionary<string, string> items = new Dictionary<string, string>();
        items.Add("1", "Item 1");
        items.Add("2", "Item 2");
        DL = new SelectList(items, "Key", "Value");
    }
}

私の開始アクションは次のとおりです。

    public ActionResult testCreate()
    {
        testCreateModel model = new testCreateModel();
        return View(model);
    }

私のRazorビュー(無関係な部分は削除されました)は次のとおりです。

@model Tasks.Models.testCreateModel

@using (Html.BeginForm()) {
<fieldset>
    <legend>testCreateModel</legend>

    <div class="editor-label">
        @Html.LabelFor(model => model.s1)
    </div>
    <div class="editor-field">
        @Html.EditorFor(model => model.s1)
    </div>

    <div class="editor-label">
        Select an item:
    </div>
    <div class="editor-field">
        @Html.DropDownList("dropdownlist", (SelectList)Model.DL)
    </div>

    <p>
        <input type="submit" value="Create" />
    </p>
</fieldset>
}

ポストバックアクションは次のとおりです。

    public ActionResult testCreate(testCreateModel model, FormCollection collection)
    {
        if (ModelState.IsValid)
        {
            Console.WriteLine("SelectedValue: ",model.DL.SelectedValue);
            Console.WriteLine("FormCollection:", collection["dropdownlist"]);
            // update database here...
        }
        return View(model);
    }

ポストバックでは、model.DL.SelectedValueはnullです。(ただし、選択したアイテムはFormCollectionから取得できますが、それだけではありません)。それ以外の場合、DLオブジェクトは引き続き適切に設定され、イミディエイトウィンドウは次のように出力されます。

model.DL
{System.Web.Mvc.SelectList}
    base {System.Web.Mvc.MultiSelectList}: {System.Web.Mvc.SelectList}
    SelectedValue: null
model.DL.Items
Count = 2
    [0]: {[1, Item 1]}
    [1]: {[2, Item 2]}
model.DL.SelectedValue
null

Q1:代わりにSelectedValueプロパティを使用するにはどうすればよいですか?

ここで、Razorビューで、Html SELECTタグの名前をDLに変更した場合(つまり、モデルのプロパティ名と同じ):

@Html.DropDownList("DL", (SelectList)Model.DL)

例外が発生します:

No parameterless constructor defined for this object. 
Stack Trace: 
[MissingMethodException: No parameterless constructor defined for this object.]
System.RuntimeTypeHandle.CreateInstance(RuntimeType type, Boolean publicOnly, Boolean noCheck, Boolean& canBeCached, RuntimeMethodHandleInternal& ctor, Boolean& bNeedSecurityCheck) +0
System.RuntimeType.CreateInstanceSlow(Boolean publicOnly, Boolean skipCheckThis, Boolean fillCache) +98
System.RuntimeType.CreateInstanceDefaultCtor(Boolean publicOnly, Boolean skipVisibilityChecks, Boolean skipCheckThis, Boolean fillCache) +241
System.Activator.CreateInstance(Type type, Boolean nonPublic) +69
System.Web.Mvc.DefaultModelBinder.CreateModel(ControllerContext controllerContext, ModelBindingContext bindingContext, Type modelType) +199
System.Web.Mvc.DefaultModelBinder.BindSimpleModel(ControllerContext controllerContext, ModelBindingContext bindingContext, ValueProviderResult 
...

Q2:なぜですか?

ありがとう。

4

2 に答える 2

11

MVCはPOSTで選択されたオプションの値のみを返すため、返される単一の値を含むプロパティが必要です。

良いアドバイスとして、ViewBagを介してSelectListsを設定してみてください。これにより、フォームに入力する必要のあるデータからViewModelsをクリーンに保つことができます。

したがって、あなたの例は次のように解決できます。

public class testCreateModel
{
    public string s1 { get; set; }
    public int SelectedValue { get; set; }
}

そしてあなたのビューでこれを行うだけです:

@Html.DropDownList("SelectedValue", (SelectList)ViewBag.DL)

GETアクションでViewBag.DLを設定する前。

Q2に関しては、デフォルトのModelBinderでは、バインドするすべての型にデフォルトのコンストラクターが必要です(ModelBinderがそれらを作成できるようにするため)。

于 2012-04-12T02:19:37.633 に答える
11

答えが選ばれましたが、私がどのようにそれをしたかを見てください。以下は、ドロップダウンを設定するときに私が通常行う方法のコードです。これは非常に単純です。ドロップダウンを作成するためのベースとして使用することをお勧めします。

ビューの上部で、ビューモデルを指定します。

@model MyProject.ViewModels.MyViewModel

私の見解では、ユーザーが選択できるすべての銀行を表示するドロップダウンリストがあります。

<table>
     <tr>
          <td><b>Bank:</b></td>
          <td>
               @Html.DropDownListFor(
                    x => x.BankId,
                    new SelectList(Model.Banks, "Id", "Name", Model.BankId),
                    "-- Select --"
               )
               @Html.ValidationMessageFor(x => x.BankId)
          </td>
     </tr>
</table>

私は常にビューのビューモデルを持っています。ドメインオブジェクトをビューに直接渡すことはありません。この場合、私のビューモデルには、データベースから入力される銀行のリストが含まれます。

public class MyViewModel
{
     // Other properties

     public int BankId { get; set; }
     public IEnumerable<Bank> Banks { get; set; }
}

私の銀行ドメインモデル:

public class Bank
{
     public int Id { get; set; }
     public string Name { get; set; }
}

次に、アクションメソッドで、ビューモデルのインスタンスを作成し、データベースから銀行リストにデータを入力します。これが完了したら、ビューモデルをビューに戻します。

public ActionResult MyActionMethod()
{
     MyViewModel viewModel = new ViewModel
     {
          // Database call to get all the banks
          // GetAll returns a list of Bank objects
          Banks = bankService.GetAll()
     };

     return View(viewModel);
}

[HttpPost]
public ActionResult MyActionMethod(MyViewModel viewModel)
{
    // If you have selected an item then BankId would have a value in it
}

これがお役に立てば幸いです。

于 2012-04-12T07:52:16.293 に答える