加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 编程开发 > asp.Net > 正文

asp.net-mvc – TimeSpan的MVC编辑器模板

发布时间:2020-12-16 06:32:51 所属栏目:asp.Net 来源:网络整理
导读:我想在我的模型中将一组文本框(小时,分钟和秒)绑定到TimeSpan.我不想在我的模型中添加小时,分钟和秒,我宁愿不将它们作为参数传递给action方法. 我发现了一些关于使用编辑器模板的讨论,但找不到一个好的例子. 解决方法 有两种方法可以做到这一点.第一种方法是
我想在我的模型中将一组文本框(小时,分钟和秒)绑定到TimeSpan.我不想在我的模型中添加小时,分钟和秒,我宁愿不将它们作为参数传递给action方法.

我发现了一些关于使用编辑器模板的讨论,但找不到一个好的例子.

解决方法

有两种方法可以做到这一点.第一种方法是实现IModelBinder,这需要您将TimeSpan作为单独的参数传递给您的操作,然后将模型的TimeSpan属性设置为它:

[HttpPost]
public ActionResult Index(YourViewModel model,[ModelBinder(typeof(TimeSpanModelBinder))] TimeSpan ts)
{
    model.LengthOfTime = ts;

    // do stuff
}

第二个是从DefaultModelBinder派生,然后允许您直接绑定到您的模型:

[HttpPost]
public ActionResult Index([ModelBinder(typeof(TimeSpanModelBinder))] YourViewModel model)
{
    // do stuff
}

实现IModelBinder的优点是您不需要定义自定义属性来标记您的属性.您也不需要在运行时动态查找模型上的属性.

从DefaultModelBinder派生的优点是,只要您使用自定义属性,它就适用于您拥有的任何模型,因此如果您需要在多个位置使用它,则可以保持操作的一致性.

第一种方法:实现IModelBinder

对于这种方法,实现IModelBinder只是意味着为BindModel方法创建一个实现:

public class TimeSpanModelBinder : IModelBinder
{
    public object BindModel(ControllerContext controllerContext,ModelBindingContext bindingContext)
    {
        if (bindingContext.ModelType != typeof(TimeSpan))
            return null;

        int hours = 0,minutes = 0,seconds = 0;

        hours = ParseTimeComponent(HoursKey,bindingContext);
        minutes = ParseTimeComponent(MinutesKey,bindingContext);
        seconds = ParseTimeComponent(SecondsKey,bindingContext);

        return new TimeSpan(hours,minutes,seconds);
    }

    public int ParseTimeComponent(string component,ModelBindingContext bindingContext)
    {
        int result = 0;
        var val = bindingContext.ValueProvider.GetValue(component);

        if (!int.TryParse(val.AttemptedValue,out result))
            bindingContext.ModelState.AddModelError(component,String.Format("The field '{0}' is required.",component));

        // This is important
        bindingContext.ModelState.SetModelValue(component,val);

        return result;
    }

    private readonly string HoursKey = "Hours";
    private readonly string MinutesKey = "Minutes";
    private readonly string SecondsKey = "Seconds";
}

注意对bindingContext.ModelState.SetModelValue的调用.此方法可确保在需要在表单上重新显示模型时,使用正确的数据重新填充模型.这很重要,因为如果用户提交的数据验证失败,它会保留再次填写所有表单字段的默认功能.

第二种方法:从DefaultModelBinder派生

您需要做的第一件事是创建一个自定义属性,您将使用该属性来标记要绑定到的模型的属性:

[AttributeUsage(AttributeTargets.Property,AllowMultiple = false)]
public class TimeSpanComponentAttribute : Attribute
{
    public override bool Match(object obj)
    {
        return obj.GetType() == typeof(TimeSpan);
    }
}

然后,您将在视图模型中使用它,如下所示:

public class YourViewModel
{
    [Required]
    public string SomeRequiredProperty { get; set; }
    [TimeSpanComponent]
    public TimeSpan LengthOfTime { get; set; }
}

然后,这允许我们在自定义模型绑定器中查找使用该属性标记的属性:

public class TimeSpanModelBinder : DefaultModelBinder
{
    public override object BindModel(ControllerContext controllerContext,ModelBindingContext bindingContext)
    {
        var model = this.CreateModel(controllerContext,bindingContext,bindingContext.ModelType);
        bindingContext.ModelMetadata.Model = model;

        var target = model.GetType()
            .GetProperties(BindingFlags.Public | BindingFlags.Instance)
            .Where(p => Attribute.IsDefined(p,typeof(TimeSpanComponentAttribute)))
            .Single();

        if (target == null)
            throw new MemberAccessException(PropertyNotFound);

        int hours = 0,bindingContext);

        target.SetValue(model,new TimeSpan(hours,seconds));

        return base.BindModel(controllerContext,bindingContext);
    }

    public int ParseTimeComponent(string component,component));

        // Again,this is important
        bindingContext.ModelState.SetModelValue(component,val);

        return result;
    }

    private readonly string HoursKey = "Hours";
    private readonly string MinutesKey = "Minutes";
    private readonly string SecondsKey = "Seconds";
    private readonly string PropertyNotFound = "Could not bind to TimeSpan property.  Did you forget to decorate " +
                                               "a property with TimeSpanComponentAttribute?";
}

请注意我们如何在BindModel中根据自定义属性找到正确的属性.此外,在我们完成对属性的绑定之后,对BindModel基本版本的调用允许默认模型绑定器处理其他所有内容.

注意

两种方法都假设您的文本框的名称分别为小时,分钟和秒.如果不是,只需更改3个私有字符串的值即可.

我通过这个编辑改变了很多,所以如果我错过了什么,请告诉我.

感谢您提出这个问题 – 我从中学到了很多东西.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读