Asp.net MVC 中使用Repeater的6种解决方案

请先阅读这里:

ASP.NET Framework Features That Are Compatible with MVC

它可能出现的Web窗体和MVC有很大的不同技术。但是,这两种技术是建立在ASP.NET的框架。因此,大多数ASP.NET框架的功能,您有用于创建应用程序都是基于Web的形式也可以提供给您作为发展中国家的MVC应用。这包括的功能,如成员资格,认证,角色和配置,它以同样的方式工作中的MVC应用因为它们在Web窗体应用程序。最ASP.NET命名空间,类和接口,可用于在ASP.NET MVC模式的应用。

 ASP.NET Framework Features That Are Incompatible with MVC

由于ASP.NET的MVC不保留状态信息通过使用视图状态,你必须寻找其他的方式来管理状态信息,如果您需要它。此外,服务器控件依赖于视图状态和传将无法正常工作设计在ASP.NET MVC模式的应用。因此,你不应该使用的控制,如GridView ,直放站和DataList控件。

源文档 <http://msdn.microsoft.com/en-us/library/dd381619.aspx>

 

准备工作:

//一个Student类:
 public class Student
    {
        
public int Number { getset; }
        
public string Name { getset; }
    }
//Dummy Data构造的绑定数据如下:
  List<Student> students = new List<Student>();
 students.Add(
new Student { Name = "lee", Number = 123 });
 students.Add(
new Student { Name = "Zen", Number = 234 });
 students.Add(
new Student { Name = "angle", Number = 101 });
 ViewData[
"Students"= students;

 

问题是什么?

      View中使用Repeater的问题其实就是绑定事件的执行,明确了这一点其实问题就很简单了.

 

方案一:页面级解决

我们设计一个View的基类,该基类在页面Load的时候完成DataBind,这样不管页面中有没有需要绑定的控件,需要绑定的控件是什么,这个方法执行完之后就会完成绑定.首先验证我们的想法:

 

//View基类
public class AutoBindViewPage : ViewPage
{
    
protected override void OnLoad(EventArgs e)
    {
      
this.DataBind();    
      
base.OnLoad(e);
    }
}

页面代码片段:

 

<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="AutoBindViewPage" %>

<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">
    Helloworld
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
    
<h2>
        Repeater Test
</h2>
    
<%=Html.Encode(ViewData["Students"])%><br />
    
<asp:Repeater ID="Repeater1" DataSource='<%#ViewData["Students"]%>' runat="server">
        
<ItemTemplate>
            Name:
<%#Eval("Name")%><br />
        
</ItemTemplate>
    
</asp:Repeater>

</asp:Content>

 

注意:Inherits="AutoBindViewPage"

跑一下程序,成功.

原理:

我们看一下继承关系:AutoBindViewPage-->ViewPage-->Page-->TemplateControl-->Control

考察一下Control类的DataBind事件:

 

protected virtual void DataBind(bool raiseOnDataBinding)
{
    
bool flag = false;
    
if (this.IsBindingContainer)
    
{
        
bool flag2;
        
object dataItem = DataBinder.GetDataItem(thisout flag2);
        
if (flag2 && (this.Page != null))
        
{
            
this.Page.PushDataBindingContext(dataItem);
            flag 
= true;
        }

    }

    
try
    
{
        
if (raiseOnDataBinding)
        
{
            
this.OnDataBinding(EventArgs.Empty);
        }

        
this.DataBindChildren();
    }

    
finally
    
{
        
if (flag)
        
{
            
this.Page.PopDataBindingContext();
        }

    }

}


 

 

 关键就在这里:this.DataBindChildren();

 

 方案二:AutoBindRepeater

     扩展ViewPage不是什么好主意,"Repeater绑定"看做一个职责,那么这个职责应该属于Repeater自己的.想到这里也就简单了,删除掉刚刚扩展的类,实现一个AutoBindRepeater:

 

namespace TestControls
{
    {
        
protected override void OnLoad(EventArgs e)
        {
            
this.DataBind();
                 
base.OnLoad(e);
        }
    }
}

 

 

页面代码片段:

 

 

<%@ Page Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage" %>

<%@ Register Namespace="TestControls" Assembly="ZenMvc" TagPrefix="My" %>
 … … 
<My:AutoBindRepeater DataSource='<%#ViewData["Students"]%>' runat="server">
        
<ItemTemplate>
            Name:
<%#Eval("Name")%><br />
        
</ItemTemplate>
    
</My:AutoBindRepeater>

跑一下,通过.

 

方案三:AutoBindRepeaterUseDataKey

方案三其实是做一点简单的改造,可以看到 DataSource='<%#ViewData["Students"]%>'在每一个Repeater中都是重复的,改造的目的就是为了简化这一语句.方法也很简单:添加对数据源的解析就可以.

 

 public class AutoBindRepeaterUseDataKey : System.Web.UI.WebControls.Repeater
    {
        
private string _dataKey;
        
public string DataKey
        {
            
get { return _dataKey; }
            
set { _dataKey = value; }
        }
        
protected override void OnLoad(EventArgs e)
        {
            ViewPage viewPage 
= (System.Web.Mvc.ViewPage)Page;
            
this.DataSource = viewPage.ViewData[DataKey];
            
this.DataBind();
                  
base.OnLoad(e);
        }
    }

 

页面代码片段:

 

 <My:AutoBindRepeaterUseDataKey DataKey="Students"  runat="server">
        
<ItemTemplate>
            Name:
<%#Eval("Name")%> &nbsp;&nbsp;
            Number:
<%#Eval("Number"%><br />
        
</ItemTemplate>
 
</My:AutoBindRepeaterUseDataKey>

 

调试,通过.

 

方案四:MVCRepeater

       细心地你一定发现了,在上面的改造中,我们已经在标准的Repeater实现中引入了MVC框架的内容.MvcFutures项目中的Microsoft.Web.Mvc.Controls里面,我们找到了一个MVCRepeater的实现:

 

<%@ Register Assembly="Microsoft.Web.Mvc" Namespace="Microsoft.Web.Mvc.Controls" TagPrefix="MVC"  %>
 
<MVC:Repeater  Name="Students" runat="server" >
    
<ItemTemplate>
     Name:
<%#Eval("Name")%><br />
    
</ItemTemplate>
    
</MVC:Repeater>

 

MVCRepeater的实现略. 

方案五:foreach语句

 

 继续追究为什么要使用Repeater,是因为我们要展示一组数据,走到这里我们的调整一下目标,不再是在MVC使用Repeater控件,而是实现在asp.net MVC 中展示一组数据.

foreach语句具有相当好的表现力:

 

 <%foreach (var item in (List<Student>)ViewData["Students"]){%>
          [Name]: 
<%=item.Name%><br/>
      
<%%>

 

方案六:MvcContrib Grid & SparkViewEngine

全面考虑MvcContrib GridSparkViewEngine也是具有技术可行性.但是是否要引入到项目中要谨慎考虑.

 

<%= Html.Grid(Model.People).Columns(column => {
             column.For(x 
=> x.Id).Named("Person ID");
             column.For(x 
=> x.Name);
             column.For(x 
=> x.DateOfBirth).Format("{0:d}");
         })
        .Attributes(style 
=> "width:100%")
         .Empty(
"There are no people.")
         .RowStart(row 
=> "<tr foo='bar'>"%>

 

源文档 <http://www.jeremyskinner.co.uk/2009/02/22/rewriting-the-mvccontrib-grid-part-2-new-syntax/>

 

<viewdata products="IEnumerable[[Product]]"/>
<ul if="products.Any()">
  
<li each="var p in products">${p.Name}</li>
</ul>
<else>
  
<p>No products available</p>
</else>

 

源文档 <http://sparkviewengine.com/>

共有0个回答