【问题标题】:ASP.net MVC - rendering a List containing different types, with a different view for each typeASP.net MVC - 呈现一个包含不同类型的列表,每种类型都有不同的视图
【发布时间】:2009-06-05 13:19:05
【问题描述】:

假设我有一个对象列表,这些对象实现了一个名为 ISummary 的接口 此列表中的对象可能具有其他属性,即。

public interface ISummary {
  Guid Id {get;set;}
  string Title {get;set;}
  DateTime Created {get;set;}
}

public class GigSummary: ISummary {
 Guid Id {get;set;}
 string Title {get;set;}
 DateTime Created {get;set;}
 string VenueName {get;set}
 string Band {get;set;}
}

public class NewsSummary: ISummary {
 Guid Id {get;set;}
 string Title {get;set;}
 DateTime Created {get;set;}
 string Author{get;set}
}

我现在将这个 Gigs 和 News Summary 对象列表(作为 ISummary 列表)作为模型传递给视图。

我想为列表中包含的每种类型使用不同的部分来呈现此列表。

ASP.NET MVC 如何做到这一点?

【问题讨论】:

    标签: asp.net-mvc partial-views


    【解决方案1】:

    我能想到的最明显的方法是:

        foreach(ISummary summ in listOfISummary) {
        Html.RenderPartial(String.Fomat("~/Views/Shared/{0}Renderer.ascx", summ.GetType.ToString()), summ, ViewData);%>
    }
    

    并使用命名约定创建强类型视图,例如 NewsSummaryRenderer.ascx。

    我希望您可以将其移至辅助方法,但我会通过扩展方法将其添加到现有辅助方法之一,而不是像之前建议的那样将其放入代码中。

    【讨论】:

    • 听起来很明智 - 我会将它包装在一个助手中
    • 实际上这在概念上是我最喜欢的答案——因为 ASP.NET MVC 是关于约定的。一个不错的小主意。
    【解决方案2】:

    您可以在视图的代码隐藏中放置一个辅助方法,然后执行以下操作:

    Type modelType = this.Model.GetType();
    
    if (modelType == typeof(NewsSummary))  this.RenderPartial("newspartial", this.Model as NewsSummary);
    else if (modelType == typeof(GigSummary)) this.RenderPartial("gigpartial", this.Model as GigSummary);
    

    【讨论】:

      【解决方案3】:

      刘易斯走在正确的轨道上。我会采取稍微不同的策略——让两个“小部件”都从一个公共基类扩展而来,该基类提供有关所涉及的视图名称的信息。然后在你的页面类中添加一个扩展方法来“渲染小部件”,它可以获得适当的视图。

      查看 Kona ASP.NET MVC 示例应用程序,了解此概念的工作示例。

      【讨论】:

        【解决方案4】:

        我会创建一个 HtmlHelper 扩展来执行此操作。下面是一些伪代码,看起来非常像 c#,实际上可能可以工作:

        public static void TemplatedList<T>(this HtmlHelper me, IEnumerable<T> items, 
        IDictionary<Type, Action<T>> templates)
        {
          foreach(var item in items)
          {
            var template = templates[item.GetType()];
            if(template != null) template(item);
          }
        }
        

        我会这样使用它:

        <% HtmlHelper.TemplatedList(ViewData.Model, new Dictionary
          {
            {typeof(GigSummary), x => %>
        
        <div class="gigSummary">
        SUP!  GIG ANNOUNCEMENT FOR <%= x.Band %>!!
        
        What:  <%= x.Title %>
        When: <%= x.Created %>
        Who: <%= x.Author %>
        </div>
        
            <%}
          // add more type/template pairs here
          }); %>
        

        【讨论】:

        • 顺便说一句,这可能看起来很奇怪,但您实际上可以将 ASP.NET 页面块反向注入代码中。同样,未经测试,可能有问题,但有可能。
        【解决方案5】:

        这是一个简单的扩展方法,您可以创建它来仅提取您需要的类型:

        public static class Extensions
        {
            public static IEnumerable<U> ExtractOfType<U, T>(this IEnumerable<T> list)
                where T : class
                where U : class
            {
                foreach (var item in list)
                {
                    if (typeof(U).IsAssignableFrom(item.GetType()))
                    {
                        yield return item as U;
                    }
                }
            }
        }
        

        测试:

        public interface IBaseInterface
        {
            string Foo { get; }
        }
        
        public interface IChildInterface : IBaseInterface
        {
            string Foo2 { get; }
        }
        
        public interface IOtherChildIntreface : IBaseInterface
        {
            string OtherFoo { get; }
        }
        
        public class BaseImplementation : IBaseInterface
        {
            public string Foo { get { return "Foo"; } }
        }
        
        public class ChildImplementation : IChildInterface
        {
            public string Foo2 { get { return "Foo2"; } }
            public string Foo { get { return "Foo"; } }
        }
        
        public class OtherChildImplementation : IOtherChildIntreface
        {
            public string OtherFoo { get { return "OtherFoo"; } }
            public string Foo { get { return "Foo"; } }
        }
        

        ....

                List<IBaseInterface> b = new List<IBaseInterface>();
                b.Add(new BaseImplementation());
                b.Add(new ChildImplementation());
                b.Add(new OtherChildImplementation());
                b.Add(new OtherChildImplementation());
        
        
                foreach (var s in b.ExtractOfType<IOtherChildIntreface, IBaseInterface>())
                {
                    Console.WriteLine(s.GetType().Name);
                }
        

        这将获取列表中您要查找的派生类型的所有项目。因此,在您的控制器中,将整个列表传递给视图。然后,让部分视图采用部分需要的类型的 IEnumerable,并在您的主视图中调用此扩展方法并将结果传递给这些单独的部分视图。

        【讨论】:

        • 我其实对接口的多种具体实现很感兴趣 :)
        • 那么对于每个具体类型都有一个单独的 Partial 视图,对于每一个,调用这个扩展方法并将结果传递给局部视图。
        猜你喜欢
        • 1970-01-01
        • 2021-12-07
        • 2013-10-13
        • 1970-01-01
        • 2019-03-29
        • 1970-01-01
        • 1970-01-01
        • 2015-06-22
        • 2011-11-21
        相关资源
        最近更新 更多