ASP.NET MVC Generic模板和集合

时间:2010-09-25 15:23:33

标签: asp.net-mvc asp.net-mvc-2

是否可以将属性应用于集合,然后在使用ViewData.ModelMetadata.Properties迭代集合成员时检测到此属性?

我想将一个属性应用于集合,以指定集合中的项目是否应该完整显示。我想在Object.ascx(处理未知类型的对象的显示)中检测到这一点,以决定要显示的详细程度。

(有关此通用模板方法的背景,请参阅brad wilson's post

例如:

public class Parent
{
   [SomeAttributeIWantToDetect]        
   public IList<Child> Children{ get; set; }
}


public class Child
{
    public string Name { get; set; }
    public string Details { get; set; }
}

object.ascx: (注意,这段代码来自ASP.NET MVC团队,而不是我的)

<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl" %>
<% if (Model == null) { %>
    <%= ViewData.ModelMetadata.NullDisplayText %>
<% } else { %>
    <table cellpadding="0" cellspacing="0" border="0">
    <% foreach (var prop in ViewData.ModelMetadata.Properties.Where(pm => pm.ShowForDisplay && !ViewData.TemplateInfo.Visited(pm))) { %>
        <% if (prop.HideSurroundingHtml) { %>
            <%= Html.Display(prop.PropertyName) %>
        <% } else { %>
            <tr>
                <td>
                    <div class="display-label" style="text-align: right;">
                        <%= prop.GetDisplayName() %>
                    </div>
                </td>
                <td>
                    <div class="display-field">
                    <!-- *********** HERE ***************-->
                    <% if (prop.AdditionalValues.ContainsKey(SomeAttributeIWantToDetectAttribute)) 
                        //Do something else.....
                        else
                     %>
                        <%= Html.Display(prop.PropertyName) %>
                    <% } %>
                    </div>
                </td>
            </tr>
        <% } %>
    <% } %>
    </table>
<% } %>

4 个答案:

答案 0 :(得分:1)

这不是MVC,它更接近传统的ASP模板

选择你想进入的营地,并留在那里

要使用MVC,您需要创建一个ViewModel,它根据特定的渲染目标表达模型

您的ViewModel应该仅使用上面的逻辑命令构建。即。

if (Model == null)
{
  x = ViewData.ModelMetadata.NullDisplayText
}
else
{
  foreach (var prop in ViewData.ModelMetadata.Properties.Where(pm => pm.ShowForDisplay && !ViewData.TemplateInfo.Visited(pm)))
  {
    if (prop.HideSurroundingHtml)
    {
      x.Items1.Add(prop.PropertyName));
    }
    else
    {
      prop.GetDisplayName()
      if (prop.AdditionalValues.ContainsKey(SomeAttributeIWantToDetectAttribute)) 
      {
        x.Items2.Add( { Text = prop.zzz, Highlight = true} ));
      }
      else
      {
        x.Items2.Add( { Text = prop.PropertyName } ));
      }
    }
  }
}

上面的代码显然是错误的,我只是试图表明你应该采用复杂的代码和逻辑并用它来构建一个ViewModel,它永远不应该在视图中

ViewModel有一个与您正在使用的渲染技术相关的简单构造(如html属性等)

视图应该只包含从ViewModel提供的简单迭代器和布局选择器,而不是实际的模型

答案 1 :(得分:1)

@UpTheCreek,你因为希望别人帮助你而感觉非常具有对抗性,但无论如何我都会给你2美分。

我的理解是,您希望能够在模型上拥有子集合。在子模型上,您将包括一些[ScaffoldColumn(“false”)]属性,但您还希望能够在父模型上放置一个属性,该属性将导致渲染器忽略ScaffoldColumn属性并仅显示一切。如果我的理解是正确的,我认为你会以错误的方式解决这个问题。您应该为需要显示不同属性的情况创建单独的视图模型。

另外,我很清楚这是否是你的意图,因为在你的代码示例中你只会隐藏输入字段而不是标签本身。也许你是想试着隐藏这个领域?

答案 2 :(得分:1)

您已多次将http://bradwilson.typepad.com/blog/2009/10/aspnet-mvc-2-templates-part-4-custom-object-templates.html与评论“我无法使用ViewModels链接,因为这是通用模板”。

我不明白你为何相信这一点。 TFD和Ryan完全正确。创建两个不同的ViewModel来包装模型,并将ScaffoldColumn属性放在ViewModel上(或者更好,完全省略这些字段)。

然后,Object.ascx会在ViewModel上检测属性(当然还有字段的存在与否),并相应地显示(或不显示)字段。

事实上,您链接的帖子的作者建议完全这样做: -

  

http://bradwilson.typepad.com/blog/2009/10/aspnet-mvc-2-templates-part-4-custom-object-templates.html#comment-6a00e54fbd8c4988340120a6396c7a970b

     

“我个人推荐   想要严格SoC的人(就像我一样)   是使用ViewModels而只放置   视图模型上的注释。   直接还有其他问题   模型绑定到LINQ to之类的东西   SQL或LINQ to Entities(例如,   如果你不小心,你可以摧毁   你的协会或无意中让   一个坏人将数据绑定到某个东西   这最初没有显示在   编辑),所以我一般都是   无论如何都推荐查看模型。“

所以: -

public class Parent
{
  public IList<Child> Children{ get; set; }
}

public class Child
{
  public String Name { get; set; }
  public String Details { get; set; }
}

// Pass this one to your "Admin" view.
public class ParentAdminViewModel
{
  private Parent _parent;
  public ParentAdminViewModel(Parent parent) { this._parent = parent; }

  public IEnumerable<Child> Children
  {
    get
    {
      return _parent.Children.Select(x => new ChildAdminViewModel(x));
    }
  }
}

public class ChildAdminViewModel
{
  private Child _child;
  public ChildAdminViewModel(Child child) { this._child = child; }

  public String Name { get { return _child.Name; } }
  public String Details { get { return _child.Details; } }
}

// Pass this one to your "User" view.
public class ParentUserViewModel
{
  private Parent _parent;
  public ParentUserViewModel(Parent parent) { this._parent = parent; }

  public IEnumerable<Child> Children
  {
    get
    {
      return _parent.Children.Select(x => new ChildUserViewModel(x));
    }
  }
}

public class ChildUserViewModel
{
  private Child _child;
  public ChildAdminViewModel(Child child) { this._child = child; }

  public String Name { get { return _child.Name; } }
  // ChildUserViewModel doesn't have a Details property,
  // so Object.ascx won't render a field for it.
}

如果你想编辑,显然你也需要连接setter。

答案 3 :(得分:0)

你能不能像这样使用反射:http://msdn.microsoft.com/en-us/library/z919e8tw.aspx