SPGridView 研究筆記 Part 1 - 基礎(chǔ)和項菜單 收藏
今年一直在為MOSS 2007寫自制ASP.NET程序, 為了讓程序的樣式更通用, 更配合MOSS自帶的風(fēng)格, 我花不了少時間調(diào)整樣式, 建立公用的CSS和JS.
一個偶然的機會, 我從一大堆"無用的"SharePoint內(nèi)置控件中找到一個可以用的控件, 就是SPGridView. SPGridView提供了MOSS的列表樣式, 給我省了不少功夫. 雖然SPGridView跟MOSS列表頁里用的ListViewWebPart長得一模一樣, 但是ListViewWebPart根本沒用到SPGridView, 所以MOSS列表頁里那個漂亮的工具條你就別想了 呵呵.
SPGridView是MOSS內(nèi)置控件中少數(shù)能脫離SharePoint List等內(nèi)置數(shù)據(jù)源使用的控件, 它繼承自System.Web.UI.WebControls.GridView, 但是使用SPGridView時必須手動把AutoGenerateColumns設(shè)成false.
1. 先創(chuàng)建一個ASP.NET Web Application(ASP.NET Web應(yīng)用程序)項目.
該項目模板已經(jīng)包含在VS2005 SP1中, 如果你不打算安裝SP1, 就需要先更新KB915364, 再安裝 Microsoft Visual Studio Web Application Projects.
2. 把引用中無用System.Web.Mobile等Assembly都去掉, 加入Microsoft.SharePoint (找不到的人去找塊豆腐撞死好了). 再建個名為 ~masterurl 的目錄, 放入一個default.master.
default.master的代碼如下
1: 2: <html> 3: <head runat="server"> 4: <asp:contentplaceholder id="PlaceHolderAdditionalPageHead" runat="server">asp:contentplaceholder> 5: head> 6: <body> 7: <form id="form1" runat="server"> 8: <asp:ContentPlaceHolder ID="PlaceHolderPageTitleInTitleArea" runat="server"> 9: asp:ContentPlaceHolder> 10: <asp:ContentPlaceHolder ID="PlaceHolderMain" runat="server"> 11: asp:ContentPlaceHolder> 12: form> 13: body> 14: html>
項目中的那個instnwnd.sql是取自Microsoft提供的SQL Server 2000 Sample Databases里的Northwind數(shù)據(jù)庫的腳本.使用腳本建立Northwind數(shù)據(jù)庫. 并將連接字符串加入web.config.
3. 建立數(shù)據(jù)訪問類NorthwindData.cs. 后面我們將使用ObjectDataSource組件來為SPGridView提供數(shù)據(jù).
1: using System; 2: using System.Data; 3: using System.Data.SqlClient; 4: using System.Configuration; 5: 6: namespace SPGridView_Demo 7: { 8: public class NorthwindData 9: { 10: private static string connectionString = null; 11: 12: public NorthwindData() 13: { 14: if(string.IsNullOrEmpty(connectionString)) 15: { 16: connectionString = ConfigurationManager.ConnectionStrings["Northwind"].ConnectionString; 17: } 18: } 19: 20: public int GetProductCount() 21: { 22: int count = 0; 23: string commandText = "SELECT COUNT(ProductId) FROM dbo.Products"; 24: SqlConnection connection = new SqlConnection(connectionString); 25: SqlCommand command = new SqlCommand(commandText, connection); 26: connection.Open(); 27: count = Convert.ToInt32(command.ExecuteScalar()); 28: connection.Close(); 29: return count; 30: } 31: 32: public DataTable GetProductList(string sortExpression) 33: { 34: DataTable dt = new DataTable(); 35: string commandText = "SELECT ProductId, ProductName, p.CategoryId, p.UnitPrice, p.Discontinued, c.CategoryName FROM dbo.Products p INNER JOIN dbo.Categories c ON p.CategoryId = c.CategoryId ORDER BY {SORT}"; 36: 37: if(sortExpression == null || sortExpression.Trim() == string.Empty) 38: { 39: sortExpression = "ProductId"; 40: } 41: 42: commandText = commandText.Replace("{SORT}", sortExpression); 43: SqlConnection connection = new SqlConnection(connectionString); 44: SqlDataAdapter adapter = new SqlDataAdapter(commandText, connection); 45: connection.Open(); 46: adapter.Fill(dt); 47: connection.Close(); 48: return dt; 49: } 50: 51: public DataTable GetProductList(int startRowIndex, int maximumRows, string sortExpression) 52: { 53: DataTable dt = new DataTable(); 54: string commandText = "SELECT * FROM (SELECT ProductId, ProductName, p.CategoryId, UnitPrice, p.Discontinued, c.CategoryName, ROW_NUMBER() OVER (ORDER BY {SORT}) AS RowNumber FROM dbo.Products p INNER JOIN dbo.Categories c ON p.CategoryId = c.CategoryId) a WHERE RowNumber BETWEEN @StartRowIndex + 1 AND @StartRowIndex + @MaximumRows"; 55: 56: if(sortExpression == null || sortExpression.Trim() == string.Empty) 57: { 58: sortExpression = "ProductId"; 59: } 60: 61: commandText = commandText.Replace("{SORT}", sortExpression); 62: SqlConnection connection = new SqlConnection(connectionString); 63: SqlDataAdapter adapter = new SqlDataAdapter(commandText, connection); 64: adapter.SelectCommand.Parameters.Add(new SqlParameter("@StartRowIndex", startRowIndex)); 65: adapter.SelectCommand.Parameters.Add(new SqlParameter("@MaximumRows", maximumRows)); 66: connection.Open(); 67: adapter.Fill(dt); 68: connection.Close(); 69: return dt; 70: } 71: } 72: }
4. 創(chuàng)建 SPGVP1.aspx
我們先試著綁些數(shù)據(jù)給SPGridView, 再發(fā)布到MOSS里看看效果吧.
代碼:
1: 2: 3: 4: <asp:Content ID="Content1" ContentPlaceHolderID="PlaceHolderAdditionalPageHead" runat="server"> 5: asp:Content> 6: <asp:Content ID="Content2" ContentPlaceHolderID="PlaceHolderPageTitleInTitleArea" runat="server"> 7: asp:Content> 8: <asp:Content ID="Content3" ContentPlaceHolderID="PlaceHolderMain" runat="server"> 9: <cc1:SPGridView ID="SPGridView1" runat="server" AutoGenerateColumns="False" DataSourceID="ObjectDataSource1"> 10: <Columns> 11: <cc1:SPBoundField DataField="ProductId" HeaderText="Product ID" SortExpression="ProductId" /> 12: <asp:HyperLinkField DataTextField="ProductName" DataNavigateUrlFields="ProductId" DataNavigateUrlFormatString="#{0}" HeaderText="Product Name" SortExpression="ProductName" /> 13: <cc1:SPBoundField DataField="ProductName" HeaderText="Product Name" SortExpression="ProductName" /> 14: <cc1:SPBoundField DataField="CategoryName" HeaderText="Category" SortExpression="CategoryName" /> 15: <asp:BoundField DataField="UnitPrice" DataFormatString="${0:F2}" HeaderText="Unit Price" SortExpression="UnitPrice" /> 16: <asp:TemplateField HeaderText="Orderable" SortExpression="Discontinued"> 17: <itemtemplate> 18: <asp:Label id="lblDiscontinued" runat="server" text=''>asp:Label>itemtemplate> 19: asp:TemplateField> 20: Columns> 21: cc1:SPGridView> 22: <asp:ObjectDataSource ID="ObjectDataSource1" runat="server" SelectMethod="GetProductList" TypeName="SPGridView_Demo.NorthwindData" SortParameterName="sortExpression">asp:ObjectDataSource> 23: asp:Content>
效果:
然后我們給Product Name列加入項菜單吧, 我們計劃給它加入2個菜單項, 1個是鏈接型View Deltail, 另1個是回發(fā)型Order Now. 覺得不過癮再加個帶!號的Order Now, 用于區(qū)別Unit Price高于$40的產(chǎn)品好了.
我們把Product Name列那行代碼
<asp:HyperLinkField DataTextField="ProductName" DataNavigateUrlFields="ProductId" DataNavigateUrlFormatString="#ProductDetail-{0}" HeaderText="Product Name" SortExpression="ProductName" />改成
<cc1:SPMenuField HeaderText="Product Name" MenuTemplateId="mtProduct" SortExpression="ProductName" TextFields="ProductName" TokenNameAndValueFields="PID=ProductId,PNAME=ProductName" NavigateUrlFields="ProductId" NavigateUrlFormat="#ProductDetail-{0}" />基中MenuTemplateId屬性指定了一個菜單模板(MenuTemplate), 菜單模板也是一個SharePoint控件類.將下面的代碼加到SPGridView代碼之外.
<cc1:MenuTemplate ID="mtProduct" runat="server"> <cc1:MenuItemTemplate ID="mitView" runat="server" Text="View Detail" ClientOnClickNavigateUrl="#ProductDetail-%PID%" /> <cc1:MenuItemTemplate ID="mitOrder" runat="server" Text="Order Now" /> <cc1:MenuItemTemplate ID="mitOrderWarn" runat="server" Text="Order Now" ImageUrl="/_layouts/images/exclaim.gif" />cc1:MenuTemplate>
注意: ID為mitView的菜單項模板使用了ClientOnClickNavigateUrl屬性來指定此菜單項的連接, 它類似與HyperLinkField的DataNavigateUrlFormatString屬性, 但是變量標(biāo)識是%Alias%, 而不是{index}或列名. 這里的數(shù)據(jù)別名(Alias)是在調(diào)用此菜單模板的SPMenuField的TokenNameAndValueFields指定的, 格式為 "別名1=列名1,別名2=列名2,...".
特別注意: 我們使用了PNAME 代表ProductName的數(shù)據(jù), 如果數(shù)據(jù)里包含單/雙引號等字符, 會導(dǎo)致菜單項失靈. 因為最終控件生成的HTML代碼將是 location.href='XXXXX' 或 ''__doPostBack('YYYYYY')". 哈! 像JS注入吧~.
然后我們在SPGridVIew的OnRowDataBound事件中寫些判斷代碼來控制不同情況下菜單模板的顯示. 我們不打算讓用戶訂購Discontinued的產(chǎn)品, 并在訂購菜單項中使用!號圖標(biāo)提示該產(chǎn)品單價超過了$40.
protected void SPGridView1_RowDataBound(object sender, GridViewRowEventArgs e)
{
if(e.Row.RowType == DataControlRowType.DataRow)
{
Microsoft.SharePoint.WebControls.Menu menu = e.Row.Cells[1].Controls[0] as Microsoft.SharePoint.WebControls.Menu;
if(menu != null)
{
bool discontinued = Convert.ToBoolean(DataBinder.Eval(e.Row.DataItem, "Discontinued"));
decimal unitPrice = Convert.ToDecimal(DataBinder.Eval(e.Row.DataItem, "UnitPrice"));
if(discontinued)
{
menu.HiddenMenuItems.Add(this.mitOrder);
menu.HiddenMenuItems.Add(this.mitOrderWarn);
}
if(unitPrice >= 40m)
{
menu.HiddenMenuItems.Add(this.mitOrder);
}
else
{
menu.HiddenMenuItems.Add(this.mitOrderWarn);
}
}
}
}
讓我們來看看現(xiàn)在實現(xiàn)了的效果.
我們還需要給Order Now菜單項添加回發(fā)行為.
protected override void OnInit(EventArgs e)
{
base.OnInit(e);
this.mitOrder.ClientOnClickUsingPostBackEventFromControl(this.SPGridView1, "Order:%PID%");
this.mitOrderWarn.ClientOnClickUsingPostBackEventFromControl(this.SPGridView1, "Order:%PID%");
}這樣我們的Order Now菜單項的點擊行為會變成 __doPostBack('ctl00$PlaceHolderMain$SPGridView1','Order:22') 的樣子. 現(xiàn)在我們加入代碼來響應(yīng)這些回發(fā)操作.
private void Order(string pid)
{
Response.Write(pid + " is ordered.");
}
protected override void RaisePostBackEvent(IPostBackEventHandler sourceControl, string eventArgument)
{
base.RaisePostBackEvent(sourceControl, eventArgument);
if(eventArgument == null || eventArgument.Trim() == string.Empty)
{
return;
}
if(eventArgument.Contains(":"))
{
int posIndex = eventArgument.IndexOf(":");
string commandName = eventArgument.Substring(0, posIndex);
string argument = eventArgument.Remove(0, posIndex + 1);
switch(commandName)
{
case "Order":
this.Order(argument);
break;
}
this.SPGridView1.DataBind();
}
}
Isn't it amazing?
完整代碼:
<script runat="server"> 1: 2: private void Order(string pid) 3: { 4: Response.Write(pid + " is ordered."); 5: } 6: 7: protected override void RaisePostBackEvent(IPostBackEventHandler sourceControl, string eventArgument) 8: { 9: base.RaisePostBackEvent(sourceControl, eventArgument); 10: 11: if(eventArgument == null || eventArgument.Trim() == string.Empty) 12: { 13: return; 14: } 15: 16: if(eventArgument.Contains(":")) 17: { 18: int posIndex = eventArgument.IndexOf(":"); 19: string commandName = eventArgument.Substring(0, posIndex); 20: string argument = eventArgument.Remove(0, posIndex + 1); 21: 22: switch(commandName) 23: { 24: case "Order": 25: this.Order(argument); 26: break; 27: } 28: 29: this.SPGridView1.DataBind(); 30: } 31: } 32: 33: protected override void OnInit(EventArgs e) 34: { 35: base.OnInit(e); 36: 37: this.mitOrder.ClientOnClickUsingPostBackEventFromControl(this.SPGridView1, "Order:%PID%"); 38: this.mitOrderWarn.ClientOnClickUsingPostBackEventFromControl(this.SPGridView1, "Order:%PID%"); 39: } 40: 41: protected void SPGridView1_RowDataBound(object sender, GridViewRowEventArgs e) 42: { 43: if(e.Row.RowType == DataControlRowType.DataRow) 44: { 45: Microsoft.SharePoint.WebControls.Menu menu = e.Row.Cells[1].Controls[0] as Microsoft.SharePoint.WebControls.Menu; 46: 47: if(menu != null) 48: { 49: bool discontinued = Convert.ToBoolean(DataBinder.Eval(e.Row.DataItem, "Discontinued")); 50: decimal unitPrice = Convert.ToDecimal(DataBinder.Eval(e.Row.DataItem, "UnitPrice")); 51: 52: if(discontinued) 53: { 54: menu.HiddenMenuItems.Add(this.mitOrder); 55: menu.HiddenMenuItems.Add(this.mitOrderWarn); 56: } 57: 58: if(unitPrice >= 40m) 59: { 60: menu.HiddenMenuItems.Add(this.mitOrder); 61: } 62: else 63: { 64: menu.HiddenMenuItems.Add(this.mitOrderWarn); 65: } 66: } 67: } 68: }script>
<asp:Content ID="Content1" ContentPlaceHolderID="PlaceHolderAdditionalPageHead" runat="server">
asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="PlaceHolderPageTitleInTitleArea" runat="server">
asp:Content>
<asp:Content ID="Content3" ContentPlaceHolderID="PlaceHolderMain" runat="server">
<cc1:SPGridView ID="SPGridView1" runat="server" AutoGenerateColumns="False" DataSourceID="ObjectDataSource1" OnRowDataBound="SPGridView1_RowDataBound">
<Columns>
<cc1:SPBoundField DataField="ProductId" HeaderText="Product ID" SortExpression="ProductId" />
<cc1:SPMenuField HeaderText="Product Name" MenuTemplateId="mtProduct" SortExpression="ProductName" TextFields="ProductName" TokenNameAndValueFields="PID=ProductId,PNAME=ProductName" NavigateUrlFields="ProductId" NavigateUrlFormat="#ProductDetail-{0}" />
<cc1:SPBoundField DataField="ProductName" HeaderText="Product Name" SortExpression="ProductName" />
<cc1:SPBoundField DataField="CategoryName" HeaderText="Category" SortExpression="CategoryName" />
<asp:BoundField DataField="UnitPrice" DataFormatString="${0:F2}" HeaderText="Unit Price" SortExpression="UnitPrice" />
<asp:TemplateField HeaderText="Orderable" SortExpression="Discontinued">
<itemtemplate>
<asp:Label id="lblDiscontinued" runat="server" text=''>asp:Label>
itemtemplate>
asp:TemplateField>
Columns>
cc1:SPGridView>
<cc1:MenuTemplate ID="mtProduct" runat="server">
<cc1:MenuItemTemplate ID="mitView" runat="server" Text="View Detail" ClientOnClickNavigateUrl="#ProductDetail-%PID%" />
<cc1:MenuItemTemplate ID="mitOrder" runat="server" Text="Order Now" />
<cc1:MenuItemTemplate ID="mitOrderWarn" runat="server" Text="Order Now" ImageUrl="/_layouts/images/exclaim.gif" />
cc1:MenuTemplate>
<asp:ObjectDataSource ID="ObjectDataSource1" runat="server" SelectMethod="GetProductList" TypeName="SPGridView_Demo.NorthwindData" SortParameterName="sortExpression">asp:ObjectDataSource>
asp:Content>
本文來自CSDN博客,轉(zhuǎn)載請標(biāo)明出處:http://blog.csdn.net/ericfine/archive/2008/10/21/3118068.aspx