我一直在尋找模型綁定來解決我遇到的具體問題。我嘗試了一些在各種博客和計算器的答案中描述的方法,但我並沒有真正到達那裏。複雜的ASP.NET MVC綁定
首先,我會提出我的模型:
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屬性爲它創建一個EditorTemplate。現在我爲我的taglist編輯器使用select2.js庫,它處理現有標籤中的ajax搜索等等。這裏的問題是Select2綁定到一個隱藏字段,它將a分隔各個標籤值,並根據它是現有標籤還是新標籤使用文本或ID生成列表,如1,tag,34,my new tag
。這個輸入我想翻譯成TagList。
所以具體的問題是: 我該如何模型綁定這個單一的隱藏的輸入到我的模型的TagList屬性,並能夠輕鬆地重用這種行爲爲我所有的模型?
EDIT =>添加EditorTemplate和該模型綁定器的代碼我創建基於關安德烈的答案
我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>
我的模型綁定器(集作爲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或特別? – IvanL
@IvanL,因爲這種粘合劑不不會干擾任何其他類型,只需替換默認值即可:'ModelBinders.Bind ers.DefaultBinder = new TagListModelBinder();' – Andrei
我試過解決方案,但我遇到了異常「參數從類型'System.String'轉換爲類型'ROCME.EventDrive.Backend.Models.Shared.Tag'失敗因爲沒有類型轉換器可以在這些類型之間進行轉換。「儘管我發現預期的綁定發生了。此外,我需要以不同的方式處理ValueProviderResult,因爲.ToString()會導致類型名稱而不是實際使用的值。 – IvanL