Strange but, Try with @Value
, capital "V"
e.g. (working on MVC4)
@Html.HiddenFor(m => m.Id, new { @Value = Model.Id })
Update:
Found that @Value (capital V) is creating another attribute with "Value" along with "value", using small @value seems to be working too!
Need to check the MVC source code to find more.
Update, After going through how it works internally:
First of all forget all these workarounds (I have kept in for the sake of continuity here), now looks silly :)
Basically, it happens when a model is posted and the model is returned back to same page.
The value is accessed (and formed into html) in InputHelper method (InputExtensions.cs) using following code fragment
string attemptedValue = (string)htmlHelper.GetModelStateValue(fullName, typeof(string));
The GetModelStateValue method (in Htmlelper.cs) retrieves the value as
ViewData.ModelState.TryGetValue(key, out modelState)
Here is the issue, since the value is accessed from ViewData.ModelState
dictionary.
This returns the value posted from the page instead of modified value!!
i.e. If your posted value of the variable (e.g. Person.Id) is 0 but you set the value inside httpPost action (e.g. Person.Id = 2), the ModelState still retains the old value "0" and the attemptedValue contains "0" ! so the field in rendered page will contain "0" as value!!
Workaround if you are returning model to same page : Clear the item from ModelState,
e.g.
ModelState.Remove("Id");
This will remove the item from dictionary and the ViewData.ModelState.TryGetValue(key, out modelState) returns null, and the next statement (inside InputExtensions.cs) takes the actual value (valueParameter) passed to HiddenFor(m => m.Id)
this is done in the following line in InputExtensions.cs
tagBuilder.MergeAttribute("value", attemptedValue ?? ((useViewData) ? htmlHelper.EvalString(fullName, format) : valueParameter), isExplicitValue);
Summary:
Clear the item in ModelState using:
ModelState.Remove("...");
Hope this is helpful.