如何在剃刀视图引擎中获取集合中项目的元数据?

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


我的索引视图通常接受一个IEnumerable<object>或IPagedList<object>集合。在我看来,我希望能够评估集合中每个object/record的 ModelMetadata以确定是否object应该显示该属性。


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


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; }

}

然后我的Index.cshtml视图将接受IPagedList<DisplayPersonViewModel>集合中的每条记录,我想显示用ShowOnIndexView属性修饰的属性的值。


通常,我可以使用这样的方法来评估我认为的 ModelMetadata


@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);

        }

}

然而与评估问题ModelMetadata的IPagedList<DisplayPersonViewModel>是,它给了我关于集合本身不是泛型类型或集合中的单一模式的信息。换句话说,我得到了诸如总页数、每页项目数、总记录数之类的信息......



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


SMILET
浏览 155回答 1
1回答

慕森王

我将通过建议您不要使用此类代码污染您的视图来介绍此答案。更好的解决方案是创建一个自定义HtmlHelper扩展方法来生成 html,这为您提供了更大的灵活性,可以进行单元测试,并且可以重用。您需要更改的第一件事是视图中的模型声明@model object否则你会抛出这个异常(List<DisplayPersonViewModel>不是IEnumerable<object>或IPagedList<object>,但它是object)需要注意的是,目前尚不清楚,如果你想ModelMetadata为type在集合或集合中的每个项目,所以我既包括,加代码,获取type@model object@{&nbsp; &nbsp; var elements = ViewData.ModelMetadata.Properties.Where(metadata => !metadata.IsComplexType && !ViewData.TemplateInfo.Visited(metadata)).OrderBy(x => x.Order).ToList();&nbsp; &nbsp; // Get the metadata for the model&nbsp; &nbsp; var collectionMetaData = ViewData.ModelMetadata;&nbsp; &nbsp; // Get the collection type&nbsp; &nbsp; Type type = collectionMetaData.Model.GetType();&nbsp; &nbsp; // Validate its a collection and get the type in the collection&nbsp; &nbsp; if (type.IsGenericType)&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; type = type.GetInterfaces().Where(t => t.IsGenericType)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .Where(t => t.GetGenericTypeDefinition() == typeof(IEnumerable<>))&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .Single().GetGenericArguments()[0];&nbsp; &nbsp; }&nbsp; &nbsp; else if (type.IsArray)&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; type = type.GetElementType();&nbsp; &nbsp; }&nbsp; &nbsp; else&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; // its not a valid model&nbsp; &nbsp; }&nbsp; &nbsp; // Get the metadata for the type in the collection&nbsp; &nbsp; ModelMetadata typeMetadata = ModelMetadataProviders.Current.GetMetadataForType(null, type);}....@foreach (var element in collectionMetaData.Model as IEnumerable)){&nbsp; &nbsp; // Get the metadata for the element&nbsp; &nbsp; ModelMetadata elementMetadata = ModelMetadataProviders.Current.GetMetadataForType(() => element, type);&nbsp; &nbsp; ....请注意,使用反射来确定循环的每次迭代中是否存在该属性是低效的,我建议您这样做一次(基于typeMetadata)。然后您可以(例如)生成一个bool值数组,然后在循环中使用索引器来检查值)。更好的选择是让您的ShowOnIndexView属性实现IMetadataAware并向AdditionalValuesof添加一个值,ModelMetadata以便var onIndex根本不需要代码。有关实现的示例IMetadataAware,请参阅CustomAttribute 反映 html 属性 MVC5
打开App,查看更多内容
随时随地看视频慕课网APP