Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/274.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/asp.net-mvc/14.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何在razor视图引擎中获取集合中项目的元数据?_C#_Asp.net Mvc_Razor_Asp.net Mvc 5_Modelmetadata - Fatal编程技术网

C# 如何在razor视图引擎中获取集合中项目的元数据?

C# 如何在razor视图引擎中获取集合中项目的元数据?,c#,asp.net-mvc,razor,asp.net-mvc-5,modelmetadata,C#,Asp.net Mvc,Razor,Asp.net Mvc 5,Modelmetadata,我有一个项目是用ASP.NET MVC 5框架顶部的C#编写的。我正在尝试将视图与视图模型分离,以便使视图可重用。通过大量使用EditorTemplates,我可以通过评估ModelMetadata和模型上每个属性的数据注释属性,然后呈现页面来创建所有标准视图(即创建、编辑和详细信息)。我唯一困惑的是如何呈现索引视图 我的索引视图通常接受IEnumerable或IPagedList集合。在我看来,我希望能够评估集合中每个对象/记录的ModelMetadata,以确定是否应显示对象上的属性 换句话

我有一个项目是用ASP.NET MVC 5框架顶部的
C#
编写的。我正在尝试将视图与视图模型分离,以便使视图可重用。通过大量使用
EditorTemplates
,我可以通过评估
ModelMetadata
和模型上每个属性的数据注释属性,然后呈现页面来创建所有标准视图(即创建、编辑和详细信息)。我唯一困惑的是如何呈现
索引
视图

我的索引视图通常接受
IEnumerable
IPagedList
集合。在我看来,我希望能够评估集合中每个
对象
/记录的ModelMetadata,以确定是否应显示
对象
上的属性

换句话说,我的视图模型看起来像这样

public class DisplayPersonViewModel
{
    public int Id{ get; set; }

    [ShowOnIndexView]
    public string FirstName { get; set; }

    [ShowOnIndexView]
    public string LastName { get; set; }

    [ShowOnIndexView]
    public int? Age { get; set; }

    public string Gender { get; set; }
}
@model IPagedList<object>
@{
var elements = ViewData.ModelMetadata.Properties.Where(metadata => !metadata.IsComplexType && !ViewData.TemplateInfo.Visited(metadata))
                                                .OrderBy(x => x.Order)
                                                .ToList();
}

<tr>
    @foreach(var element in elements)
    {
        var onIndex = element.ContainerType.GetProperty(element.PropertyName)
                             .GetCustomAttributes(typeof(ShowOnIndexView), true)
                             .Select(x => x as ShowOnIndexView)
                             .FirstOrDefault(x => x != null);
        if(onIndex == null) 
        {
            continue;
        }

        @Html.Editor(element.PropertyName, "ReadOnly")
    }
</tr>
public class PersonController : Controller
{
        public ActionResult Index()
        {
            // This would be a call to a service to give me a collection with items. but I am but showing the I would pass a collection to my view
            var viewModel = new List<DisplayPersonViewModel>();

            return View(viewModel);
        }
}
然后,我的
Index.cshtml
视图将接受
IPagedList
对于集合中的每个记录,我想显示用
ShowOnIndexView
属性修饰的属性的值

通常情况下,我可以使用类似这样的方法在视图中评估ModelMetadata

public class DisplayPersonViewModel
{
    public int Id{ get; set; }

    [ShowOnIndexView]
    public string FirstName { get; set; }

    [ShowOnIndexView]
    public string LastName { get; set; }

    [ShowOnIndexView]
    public int? Age { get; set; }

    public string Gender { get; set; }
}
@model IPagedList<object>
@{
var elements = ViewData.ModelMetadata.Properties.Where(metadata => !metadata.IsComplexType && !ViewData.TemplateInfo.Visited(metadata))
                                                .OrderBy(x => x.Order)
                                                .ToList();
}

<tr>
    @foreach(var element in elements)
    {
        var onIndex = element.ContainerType.GetProperty(element.PropertyName)
                             .GetCustomAttributes(typeof(ShowOnIndexView), true)
                             .Select(x => x as ShowOnIndexView)
                             .FirstOrDefault(x => x != null);
        if(onIndex == null) 
        {
            continue;
        }

        @Html.Editor(element.PropertyName, "ReadOnly")
    }
</tr>
public class PersonController : Controller
{
        public ActionResult Index()
        {
            // This would be a call to a service to give me a collection with items. but I am but showing the I would pass a collection to my view
            var viewModel = new List<DisplayPersonViewModel>();

            return View(viewModel);
        }
}
@model IPagedList
@{
var elements=ViewData.ModelMetadata.Properties.Where(元数据=>!metadata.IsComplexType&&!ViewData.TemplateInfo.visted(元数据))
.OrderBy(x=>x.Order)
.ToList();
}
@foreach(元素中的var元素)
{
var onIndex=element.ContainerType.GetProperty(element.PropertyName)
.GetCustomAttributes(typeof(ShowOnIndexView),true)
.选择(x=>x作为ShowOnIndexView)
.FirstOrDefault(x=>x!=null);
如果(onIndex==null)
{
继续;
}
@编辑器(element.PropertyName,“只读”)
}
然后我的控制器会像这样

public class DisplayPersonViewModel
{
    public int Id{ get; set; }

    [ShowOnIndexView]
    public string FirstName { get; set; }

    [ShowOnIndexView]
    public string LastName { get; set; }

    [ShowOnIndexView]
    public int? Age { get; set; }

    public string Gender { get; set; }
}
@model IPagedList<object>
@{
var elements = ViewData.ModelMetadata.Properties.Where(metadata => !metadata.IsComplexType && !ViewData.TemplateInfo.Visited(metadata))
                                                .OrderBy(x => x.Order)
                                                .ToList();
}

<tr>
    @foreach(var element in elements)
    {
        var onIndex = element.ContainerType.GetProperty(element.PropertyName)
                             .GetCustomAttributes(typeof(ShowOnIndexView), true)
                             .Select(x => x as ShowOnIndexView)
                             .FirstOrDefault(x => x != null);
        if(onIndex == null) 
        {
            continue;
        }

        @Html.Editor(element.PropertyName, "ReadOnly")
    }
</tr>
public class PersonController : Controller
{
        public ActionResult Index()
        {
            // This would be a call to a service to give me a collection with items. but I am but showing the I would pass a collection to my view
            var viewModel = new List<DisplayPersonViewModel>();

            return View(viewModel);
        }
}
公共类PersonController:Controller
{
公共行动结果索引()
{
//这将是对服务的调用,以向我提供一个包含项目的集合。但我只是在显示“我会将集合传递给我的视图”
var viewModel=新列表();
返回视图(viewModel);
}
}
但是,为
IPagedList
评估
ModelMetadata
的问题在于,它为我提供了有关集合本身的信息,而不是集合中的泛型类型或单个模型的信息。换句话说,我得到的信息有,总页数,每页项目数,总记录数

问题


如何访问集合中每一行的
ModelMetadata
信息,才能知道要显示哪些属性,不显示哪些属性?

在回答这个问题之前,我建议您不要用这种类型的代码污染视图。一个更好的解决方案是创建一个定制的
HtmlHelper
扩展方法来生成html,它为您提供了更大的灵活性,可以进行单元测试,并且是可重用的

您需要更改的第一件事是视图中的模型声明,它需要

@model object
否则您将抛出(
List
不是
IEnumerable
IPagedList
,而是
对象

请注意,不清楚您是要为集合中的
类型
还是为集合中的每个项目使用
ModelMetadata
,因此我将两者都包括在内,再加上获取
类型

@model object
@{
    var elements = ViewData.ModelMetadata.Properties.Where(metadata => !metadata.IsComplexType && !ViewData.TemplateInfo.Visited(metadata)).OrderBy(x => x.Order).ToList();

    // Get the metadata for the model
    var collectionMetaData = ViewData.ModelMetadata;
    // Get the collection type
    Type type = collectionMetaData.Model.GetType();
    // Validate its a collection and get the type in the collection
    if (type.IsGenericType)
    {
        type = type.GetInterfaces().Where(t => t.IsGenericType)
            .Where(t => t.GetGenericTypeDefinition() == typeof(IEnumerable<>))
            .Single().GetGenericArguments()[0];
    }
    else if (type.IsArray)
    {
        type = type.GetElementType();
    }
    else
    {
        // its not a valid model
    }
    // Get the metadata for the type in the collection
    ModelMetadata typeMetadata = ModelMetadataProviders.Current.GetMetadataForType(null, type);
}
....
@foreach (var element in collectionMetaData.Model as IEnumerable))
{
    // Get the metadata for the element
    ModelMetadata elementMetadata = ModelMetadataProviders.Current.GetMetadataForType(() => element, type);
    ....
@model对象
@{
var elements=ViewData.ModelMetadata.Properties.Where(metadata=>!metadata.IsComplexType&&!ViewData.TemplateInfo.visted(metadata)).OrderBy(x=>x.Order.ToList();
//获取模型的元数据
var collectionMetaData=ViewData.ModelMetadata;
//获取集合类型
Type Type=collectionMetaData.Model.GetType();
//验证其是否为集合并获取集合中的类型
if(type.IsGenericType)
{
type=type.GetInterfaces()。其中(t=>t.IsGenericType)
.Where(t=>t.GetGenericTypeDefinition()==typeof(IEnumerable))
.Single().GetGenericArguments()[0];
}
else if(键入.IsArray)
{
type=type.GetElementType();
}
其他的
{
//这不是一个有效的模型
}
//获取集合中类型的元数据
ModelMetadata typeMetadata=ModelMetadataProviders.Current.GetMetadataForType(null,type);
}
....
@foreach(collectionMetaData.Model中的var元素为IEnumerable))
{
//获取元素的元数据
ModelMetadata elementMetadata=ModelMetadataProviders.Current.GetMetadataForType(()=>元素,类型);
....

请注意,使用反射来确定循环的每个迭代中是否存在该属性是低效的,我建议您这样做一次(基于
typeMetadata
)生成一个
bool
值数组,然后在循环中使用索引器检查值)。更好的替代方法是让
ShowOnIndexView
属性实现
IMetadataAware
并向
ModelMetadata
附加值
添加一个值,以便
var-onIndex
代码完全不是必需的。有关实现
IMetadataAware
的示例,请参阅由于许多原因,您所做的是一个坏主意,包括使代码难以进行单元测试。该代码属于自定义
HtmlHelper
方法,而不是视图。并且您注意到,您希望显示该值,在这种情况下,您为什么要是一个
EditorTemplate
(相对于
DisplayTemplate
)@StephenMuecke助手。但是如何编写助手并访问我的模型行呢?这取决于