繁体   English   中英

复杂的ASP.NET MVC绑定

[英]Complex ASP.NET MVC Binding

我一直在研究模型绑定以解决我遇到的特定问题。 我尝试了各种博客和stackoverflow答案中描述的一些方法,但是我并没有真正到达那里。

首先,我将介绍我的模型:

public class CampaignModel
{
    [Required]
    [StringLength(24)]
    [Display(Name = "CampaignModel_Name", Prompt = "CampaignModel_Name", ResourceType = typeof(CampaignResources))]
    public string Name { get; set; }

    [StringLength(255)]
    [Display(Name = "CampaignModel_Description", Prompt = "CampaignModel_Description", ResourceType = typeof(CampaignResources))]
    public string Description { get; set; }

    [Required]
    [DataType(DataType.Date)]
    [Display(Name = "CampaignModel_StartDate", ResourceType = typeof(CampaignResources))]
    public DateTime StartDate { get; set; }

    [Required]
    [DataType(DataType.Date)]
    [Display(Name = "CampaignModel_EndDate", ResourceType = typeof(CampaignResources))]
    public DateTime EndDate { get; set; }

    [Display(Name = "CampaignModel_Tags", Prompt = "CampaignModel_Tags", ResourceType = typeof(CampaignResources))]
    public TagList Tags { get; set; }
}

因此,这是一个相当基本的模型,除了最后一个属性TagList。 现在,将来我的模型将分配一个TagList,所以这对我来说非常重要。 TagList就是这样:

public class TagList : List<Tag>
{
}

我创建此类是为了能够轻松为其创建EditorTemplate,而无需放置UIHint属性。 现在,我将select2.js库用于标记列表编辑器,该库可处理现有标记中的Ajax搜索等。 这里的问题是Select2绑定到一个隐藏字段,在其中它用a分隔各种标记值,并根据它是现有标记还是新标记,使用文本或id生成列表,如1,tag,34,my new tag 我想将此输入转换为TagList。

因此,具体的问题是: 如何将这个隐藏的输入模型绑定到模型的TagList属性中,并能够轻松地对所有模型重用此行为?

编辑=>添加基于Andrei的答案创建的EditorTemplate和ModelBinder的代码

我的EditorTemplate(省略的js)

<div class="form-group">
    @Html.Label(string.Empty, ViewData.ModelMetadata.DisplayName, new { @class = "col-md-3 control-label" })
    <div class="col-md-9">
        @Html.Hidden(string.Empty, ViewData.TemplateInfo.FormattedModelValue, new { @class = "form-control select2" })
    </div>
</div>

我的ModelBinder(在global.asax中设置为DefaultModelBinder)

public class TagListModelBinder : DefaultModelBinder
{
    protected override void BindProperty(
        ControllerContext controllerContext,
        ModelBindingContext bindingContext,
        PropertyDescriptor propertyDescriptor)
    {
        if (propertyDescriptor.PropertyType == typeof(TagList))
        {
            ValueProviderResult value = bindingContext.ValueProvider.GetValue(propertyDescriptor.Name);
            string[] rawTags = value.AttemptedValue.Split(',');
            List<long> tagIds = new List<long>();

            TagList tags = new TagList();
            foreach (string rawTag in rawTags)
            {
                long id;
                if (long.TryParse(rawTag, out id))
                {
                    // Existing tags need to be retrieved from DB
                    tagIds.Add(id);
                }
                else
                {
                    // New tags can simply be added without ID
                    tags.Add(new Tag { Text = rawTag });
                }
            }

            if (tagIds.Count > 0)
            {
                using (TagServiceClient client = new TagServiceClient())
                {
                    List<Services.TagService.Tag> existingTags = client.GetTagsByIds(tagIds);
                    tags.AddRange(existingTags.Select(t => new Tag { Id = t.id, Text = t.text }));
                }
            }

            propertyDescriptor.SetValue(bindingContext.Model, tags);
        }

        base.BindProperty(controllerContext, bindingContext, propertyDescriptor);
    }

最好的方法是从DefaultModelBinder继承并检查您要处理的属性。 如果它是TagList类型-继续并应用所需的任何逻辑。 否则,让默认实现完成工作。

public class TagListModelBinder : DefaultModelBinder
{
    protected override void BindProperty(ControllerContext controllerContext, ModelBindingContext bindingContext, System.ComponentModel.PropertyDescriptor propertyDescriptor )
    {
        if (propertyDescriptor.PropertyType == typeof(TagList))
        {
            ValueProviderResult value = bindingContext.ValueProvider.GetValue(propertyDescriptor.Name);
            string[] rawTags = value.ToString().Split(',');

            TagList tags = new TagList();
            foreach (string rawTag in rawTags)
            { 
                // for numbers - get them from DB
                // for strings - create new and store in DB
                // then add them to tags
            }

            propertyDescriptor.SetValue(bindingContext.Model, tags);
        }
        else
        {
            base.BindProperty(controllerContext, bindingContext, propertyDescriptor)
        }
    }
}

检查一下: 了解ASP.NET MVC模型绑定 希望对您有帮助!

如果要通过ajax调用将数据发布回去,则可以准备将​​数据绑定到模型属性TagList的数据。

我假设Tag类​​的结构是

public class Tag
{
    public string Name {get; set;}
    public string Id {get; set;}
}

拨打ajax电话时,您可以执行

  1. 在逗号(,)上拆分隐藏字段的值
  2. 将每个标签值添加为

    拆分列表中的Foreach标签

    data.push(“ name”:“ TagList [count] .Name”,“ value”,“要绑定的名称”);

    data.push(“ name”:“ TagList [count] .Id”,“ value”,“要绑定的ID”);

    算上++

并将此数据与ajax请求一起发布,希望它应该绑定到您的模型。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM