7

本当にわからない問題があります。私は、パブリックメンバーとしてリストを持っている非常に単純なモデルを持っています。コントローラーがポストバックでモデルから要素を削除するたびに、TextBoxFor()HTMLヘルパーが変更を取得していないようです。これらのヘルパーは何かをキャッシュしているように見えますが、私はそれに指を置くことができません。

デモ/再現はここで見つけることができます:http://broken.azurewebsites.net

再現

  1. http://broken.azurewebsites.netに移動します
  2. ゼロベースの値が入力された4つの列の値に注意してください
  3. 「テスト」ボタンを押して、リストの最初の項目を削除したページをPOSTバックします
  4. 注意「実際の」値は正しく、0要素は削除されていますが、ここでの問題はTextBoxFor()を介してレンダリングされた値にあります。その要素がもう存在しないのに、なぜそれがまだ0をレンダリングしているのか理解できません。

モデル

public class ItemViewModel
{
    public string Description { get; set; }
    public decimal? Amount { get; set; }
}

public class TestViewModel
{
    public TestViewModel()
    {
        Items = new List<ItemViewModel>();
    }

    public List<ItemViewModel> Items { get; set; }
}

コントローラ

public class HomeController : Controller
{
    public ActionResult Index()
    {
        var model = new TestViewModel();

        for (var i = 0; i < 4; i++)
        {
            model.Items.Add(new ItemViewModel { Description = i.ToString(), Amount = i });
        }

        return View(model);
    }

    [HttpPost]
    public ActionResult Index(TestViewModel model)
    {
        model.Items.RemoveAt(0);

        return View(model);
    }

}

意見

@model Demo.Models.TestViewModel
@using (Html.BeginForm())
{
    <table>
        <thead>
            <tr><td>Description</td><td>Amount</td><td>Real-Description</td><td>Real-Amount</td></tr>
        </thead>
        <tbody>
            @for (var i = 0; i < Model.Items.Count; i++)
            {
                var ii = i;
                <tr>
                    <td>@Html.TextBoxFor(m => m.Items[ii].Description)</td>
                    <td>@Html.TextBoxFor(m => m.Items[ii].Amount)</td>
                    <td>@Model.Items[ii].Description</td>
                    <td>@Model.Items[ii].Amount</td>
                </tr>
            } 
        </tbody>
    </table>
    <button>Test</button>
}
4

1 に答える 1

17

望ましい動作のために、以下のようにポストインデックスメソッドを変更します。

    [HttpPost]
    public ActionResult Index(TestViewModel model)
    {
       ModelState.Clear();     

       model.Items.RemoveAt(0);

       return View(model);
    }

理由は次のとおりです。

TextBoxForは、モデル値ではなくModelStateの投稿値にバインドします。したがって、アプリケーションでは、[テスト]ボタンを押すと、テキストボックスは既に持っている値にバインドされ、モデル値が変更された後でもポストバック時に更新されません。たとえば、最初の行のテキストボックスに0が表示され、ポストバック後もその値にバインドされたままで、基になるモデルの値が1の場合、この動作の背後にある理由は検証です。テキストボックスにintを期待していて、ユーザーが「SomeTextValue」と入力した場合、モデルバインダーはintプロパティにバインドできず、検証エラーの状態になります。次に、 「SomeTextValue」が整数ではないというエラーをユーザーに表示させます。整数を入力してくださいユーザーが入力した値がそこにあると期待するからです。

リック・シュトラールはこのブログ投稿でそれを完璧に説明しています

http://www.west-wind.com/weblog/posts/2012/Apr/20/ASPNET-MVC-Postbacks-and-HtmlHelper-Controls-ignoring-Model-Changes

そして以下のブランドウィルソン:

http://forums.asp.net/post/3688022.aspx

于 2012-12-01T17:41:10.940 に答える