我有一个通用的DateTime编辑器模板,应该使用所需的格式(“dd / MM / yyyy”)格式化我的所有DateTime属性:
@Html.TextBox(string.Empty, Model.ToString("dd/MM/yyyy"), new { @class = "datepicker" })
但由于某种原因,格式不适用于我的孩子的行为。
如果我在 MainPage .cshtml中执行@ Html.EditorFor(x => x.MyDate) 我得到了预期的结果:“23/04/2012”
如果我在 ChildAction .cshtml中执行@ Html.EditorFor(x => x.MyDate) 我得到了意外的结果:“2012-04-24”
我可以确认正在使用编辑模板,因为如果我这样改变它(注意开头的WTF字符串):
WTF @Html.TextBox(string.Empty, Model.ToString("dd/MM/yyyy"), new { @class = "datepicker" })
然后如果我在ChildAction.cshtml中执行@ Html.EditorFor(x => x.MyDate)
我得到:“WTF 2012-04-24”
有什么想法吗?
更新
为了在MVC示例应用程序中重现此错误,我发现还需要另外两件事:
public class DateTimeModelBinder : DefaultModelBinder
{
public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
var value = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);
DateTime date;
if (DateTime.TryParseExact(value.AttemptedValue, "dd/MM/yyyy", DateTimeFormatInfo.CurrentInfo, DateTimeStyles.AssumeLocal, out date))
{
return date;
}
return base.BindModel(controllerContext, bindingContext);
}
}
我假设每个人都知道如何连线。同样在MainPage.cshtml中,您必须将模型作为第二个参数传递给RenderAction
@{Html.RenderAction("Child", Model);}
当将模型作为第二个参数传递时,MVC使用模型绑定器来调用子操作(为什么?)。但是,日期的格式是MM / dd / yyyy,所以它不适用于我的模型活页夹,它假设我的所有日期都是dd / MM / yyyy格式。这就是为什么这不起作用。
但我该如何解决?日期与dd / MM / yyyy的默认格式不匹配的唯一地方是渲染子操作。
答案 0 :(得分:1)
问题
MVC尽可能使用modelstate值,但父动作的模型状态与子动作的值不同:
在父操作中,模型状态包含提交给操作的日期的字符串(valueproviderresult中的RawValue)或默认值。
当父操作将信息传递给子操作时 (renderaction)它在模型状态下传递 dateTime (RawValue in valueproviderresult)。
因此,在父操作中,如果未提交任何值,则正确使用Textbox(...)中提供的值。如果客户端以相同的格式提交了有效值,那么它似乎也可以,因为它在模型状态中采用的字符串与displaytemplate中生成的字符串相同。
但在子动作中,它使用包含日期时间而不是提交的字符串的模型状态, MVC然后使用invariantculture将该日期时间转换为字符串,因此它将显示MM / dd / yyyy(I 3年后,因为你有yyyy-MM-dd,所以价值可能在框架中发生了变化。
解决方案
您需要将模型状态中的值替换为您想要的值,或者将其替换为受影响的值。
public static void Fix(ModelStateDictionary dic, string key)
{
ModelState modelState = dic[key];
if (!modelState.Errors.Any() && modelState.Value.RawValue != null
&& (modelState.Value.RawValue is DateTime || modelState.Value.RawValue is DateTime?))
{
var sValue = ((DateTime)modelState.Value.RawValue).ToString("dd/MM/yyyy");
var value = new ValueProviderResult(sValue, sValue, CultureInfo.InvariantCulture);
dic.SetModelValue(key, value);
//or
//dic.Remove(key);
}
}
然后在您的子操作中调用该方法:
Fix(ModelState, nameof(viewModel.DateMax));