我有一个名为FileLink
的自定义属性,它使用DisplayForModel()
为具有ID值的控制器生成ActionLink
。
该属性如下所示:
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
public sealed class FileLinkAttribute : Attribute
{
public string ActionName { get; set; }
public string ControllerName { get; set; }
public string IdPropertyName { get; set; }
public FileLinkAttribute(string actionName, string controllerName, string idPropertyName)
{
ActionName = actionName;
ControllerName = controllerName;
IdPropertyName = idName;
}
}
是否在viewmodel中使用,如下所示:
public class MyViewModel
{
[HiddenInput(DisplayValue = false)]
public int? Id { get; set; }
[HiddenInput(DisplayValue = false)]
public int? TargetId { get; set; }
[FileLink("SomeAction", "SomeController", "TargetId")]
public string Name { get; set; }
}
我有一个源自MetadataProvider
的自定义DataAnnotationsModelMetadataProvider
,它将属性值放入元数据AdditionalValues中,如下所示:
// retrieve the values to generate a file link
var fileLinkAttributes = attributes.OfType<FileLinkAttribute>();
if (fileLinkAttributes.Any())
{
var fileLinkAttribute = fileLinkAttributes.First();
metadata.AdditionalValues["FileLinkAttribute"] = fileLinkAttribute;
metadata.TemplateHint = "FileLink";
}
目标是让DisplayForModel
调用下面的DisplayTemplate
来生成TargetId
中来自MyViewModel
的值的链接。因此,如果TargetId
为5,则链接将为“SomeController / SomeAction / 5”
// This DisplayTemplate for use with the "FileLinkAttribute"
//
// Usage: [FileLinkAttribute("ActionName","ControllerName","IdPropertyName")]
var fileLinkAttribute = (FileLinkAttribute)ViewData.ModelMetadata.AdditionalValues["FileLinkAttribute"];
var targetId = *<GET VALUE OF CONTAINER MODEL IdPropertyName>*;
@Html.ActionLink((string)ViewData.Model, fileLinkAttribute.ActionName, fileLinkAttribute.ControllerName, new { Id = targetId}, null)
完成所有这些后,我无法访问包含对象以从TargetId中提取属性值。我试图在Attribute中,Provider内和DisplayTemplate中执行此操作,但没有运气。
我是否有办法或地方可以访问此值以实现从包含该属性的viewmodel对象中读取属性值的意图?
答案 0 :(得分:1)
阅读此帖后,在自定义DataAnnotationsModelMetadataProvider中描述modelAccessor
的用途:
我能够将自定义提供程序中实现的这个(非常hackish)解决方案拼凑起来:
// retrieve the values to generate a file link
var fileLinkAttributes = attributes.OfType<FileLinkAttribute>();
if (fileLinkAttributes.Any())
{
var fileLinkAttribute = fileLinkAttributes.First();
// modelAccessor contains a pointer the container, but the type is not correct but contains the name of the correct type
if (modelAccessor.Target.GetType().ToString().Contains("System.Web.Mvc.AssociatedMetadataProvider"))
{
// get the container model for this metadata
FieldInfo containerInfo = modelAccessor.Target.GetType().GetField("container");
var containerObject = containerInfo.GetValue(modelAccessor.Target);
// get the value of the requested property
PropertyInfo pi = containerObject.GetType().GetProperty(fileLinkAttribute.IdPropertyName);
string idPropertyValue = pi.GetValue(containerObject, null).ToString();
fileLinkAttribute.IdPropertyValue = idPropertyValue;
}
metadata.AdditionalValues["FileLinkAttribute"] = fileLinkAttribute;
metadata.TemplateHint = "FileLink";
}
我不确定如何对Func进行反驳以获得它的实际目标,并且在此示例中类型名称全部出现,例如
“System.Web.Mvc.AssociatedMetadataProvider + LT;&GT; c__DisplayClassb”
所以我转换为一个字符串来检查它是否包含“System.Web.Mvc.AssociatedMetadataProvider”。可能不是最好的东西,但这是我能让它发挥作用的唯一方法。
哦,我还在属性中添加了第4个属性以包含值:
[AttributeUsage(AttributeTargets.Property,AllowMultiple = false,Inherited = true)] public sealed class FileLinkAttribute:Attribute { public string ActionName {get;组; } public string ControllerName {get;组; } public string IdPropertyName {get;组; } public string IdPropertyValue {get;组; }
public FileLinkAttribute(string actionName, string controllerName, string idPropertyName)
{
ActionName = actionName;
ControllerName = controllerName;
IdPropertyName = idPropertyName;
}
}
并在DisplayTemplate中执行:
var modelId = fileLinkAttribute.IdPropertyValue;
答案 1 :(得分:0)
这应该是strsing或object的编辑器模板,就像你应用属性一样。所以在~/Views/Shared/EditorTemplates/string.cshtml
内:
@model string
@{
var fileLinkAttribute = (FileLinkAttribute)ViewData.ModelMetadata.AdditionalValues["FileLinkAttribute"];
var targetId = fileLinkAttribute.IdPropertyName;
}
@Html.ActionLink(Model, fileLinkAttribute.ActionName, fileLinkAttribute.ControllerName, new { Id = targetId}, null)
并在主视图中:
@Html.EditorFor(x => x.Name)