MVC3 Child Action打破了我的DateTime编辑器模板

时间:2012-04-23 21:11:28

标签: asp.net-mvc-3

我有一个通用的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的默认格式不匹配的唯一地方是渲染子操作。

1 个答案:

答案 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));