复杂的 ASP.NET MVC 绑定
本文关键字:MVC 绑定 NET ASP 复杂 | 更新日期: 2023-09-27 17:56:02
我一直在研究模型绑定以解决我遇到的特定问题。我尝试了各种博客和堆栈溢出答案中描述的一些方法,但我并没有真正到达那里。
首先,我将展示我的模型:
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。现在将来我的模型分配将有一个标签列表,所以这对我来说相当重要。标签列表就是这样:
public class TagList : List<Tag>
{
}
我创建这个类是为了能够轻松地为它创建一个编辑器模板,而不必放置UIHint属性。现在我正在为我的标签列表编辑器使用 select2.js 库,该库处理现有标签中的 ajax 搜索等。这里的问题是 Select2 绑定到单个隐藏字段,其中它用 分隔各种标签值,并且根据它是现有标签还是新标签,它使用文本或 id 生成类似 1,tag,34,my new tag
的列表。我想将此输入转换为标签列表。
所以具体问题是:如何将此单个隐藏输入绑定到模型上的 TagList 属性中,并能够轻松地在所有模型中重用此行为?
编辑 => 添加编辑器模板的代码和我根据安德烈的答案创建的模型绑定器
我的编辑器模板(省略 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>
My 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 调用时,您可以执行
- 将
- 隐藏字段的值拆分为逗号 (,)
将每个标签值添加为
对于拆分列表中的每个标记
data.push("name": "TagList[count].名称"、"值"、"要绑定的名称");
data.push("name": "TagList[count].Id"、"值"、"要绑定的 Id");
计数++
并将此数据与 ajax 请求一起发布,希望这应该绑定到您的模型。