一連のページビューのビューステートに問題がある-Razorのページの初期ビューでは、次のように_Html.HiddenFor
_を使用しています。
_ @Html.HiddenFor(x => Model.err)
@Html.HiddenFor(x => Model.errField)
@Html.HiddenFor(x => Model.errMessage)
@Html.HiddenFor(x => Model.IsMove)
_
うまくいくようです。非表示の入力タグには正しい値が含まれています。ただし、フォーム_[HTTPPost]
_を送信し、コントローラーアクションでモデルを更新すると、..
_ model.err = transHelper.err;
model.errField = transHelper.errField;
model.errMessage = transHelper.errMessage;
return View(model);
_
非表示フィールドは更新されていないようで、初期ビューの元の値が含まれています。ただし、このような同じカミソリビュー内の別のコンテキストでこれらのフィールドを使用すると...
_ @*
this seems to not update correctly...
@Html.HiddenFor(x => Model.err)
@Html.HiddenFor(x => Model.errField)
@Html.HiddenFor(x => Model.errMessage)
@Html.HiddenFor(x => Model.IsMove)
*@
<input type="hidden" id="err" value="@Model.err" />
<input type="hidden" id="errField" value="@Model.errField" />
<input type="hidden" id="errMessage" value="@Model.errMessage" />
<input type="hidden" id="IsMove" value="@Model.IsMove" />
</div>
_
次に、入力フィールドが正しく更新されます。デバッグを支援するためにビューヘルパーを作成しましたが、すべての場合において、モデルは_HtmlHelper<TModel>
_に正しいデータを持っているようです-モデルをreturn Json(model);
として返し、データは正常でした。
この時点で私は回避策を実行していますが、_@Html.HiddenFor
_が汚れている理由は誰にもわかりません。
更新:ここに私のコントローラーアクションがあります
_ [HttpPost]
public ActionResult Index(HomePageModel model)
{
// process transaction
Transactionr transr = new Transactionr();
transr.Process(model);
model.err = transr.err;
model.errField = transr.errField;
model.errMessage = transr.errMessage;
return View(model);
}
_
私の見解は次のとおりです。
_ @model App.Models.HomePageModel
@{
ViewBag.Title = "Product Categorizer";
}
<form id="formData" method="post" action="/Home/Index">
@Html.AntiForgeryToken()
<fieldset>
<div>
@Html.HiddenFor(model => model.err)
@Html.HiddenFor(model => model.errField)
@Html.HiddenFor(model => model.errMessage)
@Html.HiddenFor(model => model.IsMove)
<input type="hidden" id="myerr" value="@Model.err" />
<input type="hidden" id="myerrField" value="@Model.errField" />
</div>
<div class="section group">
<div class="col span_2_of_2">
<div class="message" id ="message">
@if (Model.err < 0)
{
<span style="color: purple;">@Model.errMessage (@Model.err) - (@Model.errField)</span>
}
else if (Model.err > 0)
{
<span style="color:red;">@Model.errMessage (@Model.err) (@Model.errField)</span>
} else {
<span>@Model.errMessage (@Model.err) (@Model.errField)</span>
}
</div>
</div>
</div>
<div class="section group" id="workspace">
@Html.Partial("_WorkspacePartial", Model)
</div>
<div class="section group" id="details">
@Html.Partial("_DetailPartial", Model)
</div>
</fieldset>
</form>
_
私のモデルは次のとおりです。
_ public class HomePageModel
{
public int FromStore { get; set; }
// the "To" part of the copy/move transaction
public int ToStore { get; set; }
// a list of the copy/move transaction
public List<int> Details { get; set; }
// true is move false is copy
public bool IsMove { get; set; }
// current message
public int err { get; set; }
public int errField { get; set; }
public string errMessage { get; set; }
_
デフォルトのHtmlHelpersの動作(@ Html.HiddenForなど)は、説明したとおりに動作します。
つまり、投稿でViewModelに行った変更はすべて実行され、投稿から返された変更はすべてビューで受信されますが、HTMLHELPERSで再レンダリングすると、以前の投稿値が変更されたViewModel値よりも優先されます。
この動作をすばやく+汚い方法で「修正」したい場合は、HttpPost ActionMethodから戻る前にModelState.Clear()をクリアします。
Joedotnotで述べたように、これは意図した動作です。これに対する別の「クイックフィックス」は、非表示フィールドのhtmlをコーディングし、モデルの値のみを更新することです。例:
<input type="hidden" id="ErrMessage" name="ErrMessage" value="@Model.ErrMessage">
モデルプロパティと同じid
およびname
を使用すると、ポストバック後に更新された値がレンダリングされます。
私は最近、同様の問題に直面し、新しい単純なヘルパーメソッド+ 2つのオーバーロードを作成することになりました。この「機能」が迷惑な場合があるため、誰かがまだ回避策を探している場合に備えて、ここで共有しています。
public static class CustomExtensions
{
public static MvcHtmlString HiddenFor2<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression)
{
ReplacePropertyState(htmlHelper, expression);
return htmlHelper.HiddenFor(expression);
}
public static MvcHtmlString HiddenFor2<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, object htmlAttributes)
{
ReplacePropertyState(htmlHelper, expression);
return htmlHelper.HiddenFor(expression, htmlAttributes);
}
public static MvcHtmlString HiddenFor2<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, IDictionary<string, object> htmlAttributes)
{
ReplacePropertyState(htmlHelper, expression);
return htmlHelper.HiddenFor(expression, htmlAttributes);
}
private static void ReplacePropertyState<TModel, TProperty>(HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression)
{
string text = ExpressionHelper.GetExpressionText(expression);
string fullName = htmlHelper.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldName(text);
ModelStateDictionary modelState = htmlHelper.ViewContext.ViewData.ModelState;
if (modelState.ContainsKey(fullName))
{
ModelMetadata metadata = ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData);
ValueProviderResult currentValue = modelState[fullName].Value;
modelState[fullName].Value = new ValueProviderResult(metadata.Model, Convert.ToString(metadata.Model), currentValue.Culture);
}
}
}
次に、ビュー内から通常どおり使用します。
@Html.HiddenFor2(m => m.Id)
それはコレクションでも動作することを言及する価値があります。
代わりに次のように使用する必要があると思います。
@Html.HiddenFor(x => x.Err)
@Html.HiddenFor(x => x.ErrField)
@Html.HiddenFor(x => x.ErrMessage)
@Html.HiddenFor(x => x.IsMove)
あなたのモデルを見ずに、私はそれが次のように見えると仮定しています:
public class ErroViewModel
{
public string Err { get; set; }
public string ErrField { get; set; }
public string ErrMessage { get; set; }
public bool IsMove { get; set; }
}
そうでない場合は、上記のパブリックプロパティと同様でなければなりません。
更新
あなたのゲットには次のものがありますか?
public ActionResult Index(HomePageModel model)
{
var model = new HomePageModel();
return View(model);
}
また、フォームをこれから変更します。
<form id="formData" method="post" action="/Home/Index">
これに:
@using (Html.BeginForm("Index", "Home", FormMethod.Post))
{
// rest of form
}
あなたが試すことができます
<input type="hidden" id="SomeFieldID" name="SomeFieldID" value="@Model.SomeFieldID" />
同様の問題があり、このように解決しました。
@Html.TextBoxFor(m => m.Email, new { onclick = "this.select()", Value = Model.Email, Placeholder = "E-Mail" })