none
在SharePoint中使用自定义的服务器控件(Web Control) RRS feed

  • 常规讨论

  • SharePoint的开发中,我们经常需要自己开发一些服务器控件,然后把它添加到MOSS的页面上。

    SharePoint服务器控件的开发跟普通的asp.net服务器控件没有区别,只不过是在部署的时候需要进行一些特别的配置。

    下面拿一个具体的例子来说明这个过程。

    以下的示例是一个自定义的导航服务器控件(WebFolderNavigation),这个导航控件的第一级为所有显示在导航栏上的列表或文档库链接,列表或文档库链接的子级为相应的文件夹。效果图如下:


    Step1: 新建一个Asp.net Server Control项目,名称为CodeArt.SharePoint.WebControls。(或普通的类库项目,添加System.Web的引用。)

     

    Step2:因为WebFolderNavigation控件需要访问SharePoint的对象模型,所有添加对Microsoft.SharePoint.dll的引用。

     

    Step3: WebFolderNavigation控件的代码如下:

    using System;

    using System.Collections.Generic;

    using System.Text;

    using System.Web;

    using System.Web.UI.WebControls;

    using System.Web.UI.HtmlControls;

    using Microsoft.SharePoint;

    using Microsoft.SharePoint.Navigation;

    using System.Web.UI;

    namespace CodeArt.SharePoint.WebControls

    {

    /// <summary>

    /// 当前站点文件夹导航

    /// </summary>

    public class WebFolderNavigation : Menu

    {

    const String SORT_FIELD_NAME = "排序号";

    const String SHOW_SUB_FIELD_NAME = "显示子栏目";

    private bool _EnableSort = false;

    public bool EnableSort

    {

    get { return _EnableSort; }

    set { _EnableSort = value; }

    }

     

    private int _MaxFolderDepth = 2;

    public int MaxFolderDepth

    {

    get { return _MaxFolderDepth; }

    set { _MaxFolderDepth = value; }

    }

    protected override void CreateChildControls()

    {

    if ( this.Items.Count > 0)

    return;

    base.CreateChildControls();

    SPWeb web = SPContext.Current.Web;

    string webUrl = web.ServerRelativeUrl;

    if (!webUrl.EndsWith("/"))

    webUrl += "/";

    Dictionary<string, SPList> allVisibleList = new Dictionary<string, SPList>();

    foreach (SPList list in web.Lists)

    {

    if (list.OnQuickLaunch)

    allVisibleList.Add(list.DefaultViewUrl.ToLower() , list);

    }

    List<SPNavigationNode> navLinks = new List<SPNavigationNode>();

    foreach (SPNavigationNode levelOneNode in web.Navigation.QuickLaunch)

    {

    if (levelOneNode.IsVisible)

    {

    foreach (SPNavigationNode levelTwoNode in levelOneNode.Children)

    {

    if (levelTwoNode.IsVisible)

    {

    navLinks.Add(levelTwoNode);

    }

    }

    }

    }

    foreach (SPNavigationNode node in navLinks)

    {

    if (allVisibleList.ContainsKey(node.Url.ToLower()))

    {

    SPList list = allVisibleList[node.Url.ToLower()];

     

    MenuItem rootItem = new MenuItem();

    rootItem.Text = list.Title;

    rootItem.ToolTip = list.Description ;

     

    rootItem.NavigateUrl = list.DefaultViewUrl;

    this.Items.Add(rootItem);

     

    string showSubFieldName = getShowSubFieldName(list);

     

    if (EnableSort)

    {

    string sortFieldName = getSortFieldName(list);

     

    if (sortFieldName == "")

    CreateItem(list.RootFolder, rootItem.ChildItems, webUrl, 1, showSubFieldName);

    else

    CreateItem(list.RootFolder, rootItem.ChildItems, webUrl, sortFieldName, 1, showSubFieldName);

    }

    else

    {

    CreateItem(list.RootFolder, rootItem.ChildItems, webUrl, 1, showSubFieldName);

    }

    }

    else

    {

    CreateItemByNavigationNode(this.Items, node);

    }

    }

    }

    void CreateItemByNavigationNode(MenuItemCollection items, SPNavigationNode node)

    {

    MenuItem item = new MenuItem();

    item.Text = node.Title ;

    item.NavigateUrl = node.Url ;

    items.Add(item);

    if (node.Children.Count == 0) return;

    foreach (SPNavigationNode n in node.Children )

    {

    CreateItemByNavigationNode(item.ChildItems, n);

    }

    }

    string getSortFieldName(SPList list)

    {

    if (list.Fields.ContainsField(SORT_FIELD_NAME))

    {

    SPField f = list.Fields.GetField(SORT_FIELD_NAME);

    return f.InternalName;

    }

    return "";

    }

    string getShowSubFieldName(SPList list)

    {

    if (list.Fields.ContainsField( SHOW_SUB_FIELD_NAME ))

    {

    SPField f = list.Fields.GetField(SHOW_SUB_FIELD_NAME);

    return f.InternalName;

    }

    return "";

    }

    bool ShowSubFolder(SPFolder folder, string showSubFieldName)

    {

    SPListItem folderItem = folder.Item;

    if (folderItem == null) return true;

     

    if ( folderItem.Fields.ContainsField(showSubFieldName))

    {

    object value = folder.Item[showSubFieldName];

    if( value == null )

    return false ;

    else

    return value.ToString().ToLower() == "true";

    }

    else

    {

    return true;

    }

    }

    void CreateItem(SPFolder folder, MenuItemCollection items, string webUrl, int depth, string showSubFieldName)

    {

    if (!ShowSubFolder(folder, showSubFieldName)) return;

     

    if (folder.SubFolders.Count == 0) return;

    foreach (SPFolder f in folder.SubFolders)

    {

    if (f.Item==null) continue; //说明是隐藏文件夹 

    MenuItem item = new MenuItem();

    item.Text = f.Name;

    item.NavigateUrl = f.ServerRelativeUrl;

    items.Add(item);

    if (depth < this.MaxFolderDepth )

    {

    CreateItem(f, item.ChildItems, webUrl, depth + 1, showSubFieldName);

    }

    }

    }

    void CreateItem(SPFolder folder, MenuItemCollection items, string webUrl, string sortField, int depth, string showSubFieldName)

    {

    if (!ShowSubFolder(folder, showSubFieldName)) return;

    if (folder.SubFolders.Count == 0) return;

    IList<SPFolder> folders = SPUtil.GetSortedFolders(folder.SubFolders , sortField );

    foreach (SPFolder f in folders)

    {

    if (f.Item==null) continue;

    MenuItem item = new MenuItem();

    item.Text = f.Name;

    item.NavigateUrl = f.ServerRelativeUrl;

    items.Add(item);

    if (depth < MaxFolderDepth)

    CreateItem(f, item.ChildItems, webUrl, sortField, depth + 1, showSubFieldName);

    }

    }

    }

    }

     

    代码中用到的SPUtil类如下:

     

    SPUtil
    /// <summary>
        
    /// 
        
    /// </summary>
        public class SPUtil
        {
            
    static public bool IsHiddenFolder(SPFolder f)
            {
                
    return f.Item == null;
                
    //return f.Properties.Count < 20;
            }

            
    static public string GetWebUrl( SPWeb web )
            {
                
    string webUrl = web.Url;
                
    if (!webUrl.EndsWith("/"))
                    webUrl 
    += "/";

                
    return webUrl;
            }

            
    public static StringDictionary GetFieldDictionary(SPList list)
            {
                StringDictionary fields 
    = new StringDictionary();

                
    foreach (SPField f in list.Fields)
                {
                    
    if (fields.ContainsKey(f.Title)) continue;

                    fields.Add(f.Title, f.InternalName);
                }

                
    return fields;
            }


            
    static public int[] GetSelectedItemIDs( SPList list )
            {
                
    return GetSelectedItemIDs( list.ID.ToString() ) ;
            }

            
    static public int[] GetSelectedItemIDs(string listId )
            {
                
    if (System.Web.HttpContext.Current == null)
                    
    throw new SPException("context is null.");

                
    string ids = System.Web.HttpContext.Current.Request["spItemSelectionCheckBox_" + listId];

                
    if (ids == null || ids == "")
                    
    return null;

                String[] arr 
    = ids.Split(',');

                
    int[] intIDs = new int[arr.Length];

                
    for (int i = 0; i < arr.Length; i++)
                {
                    intIDs[i] 
    = Convert.ToInt32(arr[i]);
                }

                
    return intIDs;
            }

            
    /// <summary>
            
    /// 修改视图中的查询条件部分
            
    /// </summary>
            
    /// <param name="doc"></param>
            
    /// <param name="query"></param>
            static public void ChangeSchemaXmlQuery(XmlDocument doc, string query)
            {
                
    if (String.IsNullOrEmpty(query)) return;

                
    string innerQuery = GetInnerQuery(query);
                
    if (innerQuery == ""return;

                XmlNode queryNode 
    = doc.DocumentElement.SelectSingleNode("Query");
                
    //queryNode.InnerXml = qxml;

                XmlNode whereNode 
    = queryNode.SelectSingleNode("Where");

                
    if (whereNode != null)
                    queryNode.RemoveChild(whereNode);

                XmlNode newWhereNode 
    = doc.CreateElement("Where");
                newWhereNode.InnerXml 
    = innerQuery;

                queryNode.AppendChild(newWhereNode);

                XmlNode ViewEmptyNode 
    = doc.DocumentElement.SelectSingleNode("ViewEmpty");

                ViewEmptyNode.InnerXml 
    = "<HTML><![CDATA[<font color='red'><b>未找到符合查询条件的记录。</b></font>]]></HTML>";

            }

            
    /// <summary>
            
    /// 设置视图xml中的查询条件
            
    /// </summary>
            
    /// <param name="doc"></param>
            
    /// <param name="query1">条件1</param>
            
    /// <param name="query2">条件2</param>
            static public void ChangeSchemaXmlQuery(XmlDocument doc, string query1 , string query2)
            {
                
    string query = "";

                
    string innerQuery = GetInnerQuery(query1);           

                
    string innerQuery2 = GetInnerQuery(query2);

                
    if (innerQuery == "" && innerQuery2 == "" ) return;

                
    if (innerQuery != "" && innerQuery2 != "")
                    query 
    = "<And>" + innerQuery + innerQuery2 + "</And>" ;
                
    else
                    query 
    = innerQuery + innerQuery2 ;

                XmlNode queryNode 
    = doc.DocumentElement.SelectSingleNode("Query");
                
    //queryNode.InnerXml = qxml;

                XmlNode whereNode 
    = queryNode.SelectSingleNode("Where");

                
    if (whereNode != null)
                    queryNode.RemoveChild(whereNode);

                XmlNode newWhereNode 
    = doc.CreateElement("Where");
                newWhereNode.InnerXml 
    = query;

                queryNode.AppendChild(newWhereNode);

                XmlNode ViewEmptyNode 
    = doc.DocumentElement.SelectSingleNode("ViewEmpty");

                ViewEmptyNode.InnerXml 
    = "<HTML><![CDATA[<font color='red'><b>未找到符合查询条件的记录。</b></font>]]></HTML>";

            }


            
    static string GetInnerQuery(string q)
            {
                XmlDocument doc 
    = new XmlDocument();
                doc.LoadXml(
    "<Query>" + q + "</Query>");

                XmlNode whereNode 
    = doc.DocumentElement.SelectSingleNode("Where");

                
    if (whereNode != null)
                    
    return whereNode.InnerXml;
                
    else
                    
    return "";
            }

     

            
    /// <summary>
            
    /// 获取ViewXml中的排序结
            
    /// </summary>
            
    /// <param name="viewXml"></param>
            
    /// <returns></returns>
           public static string GetOrderBySection( string viewXml )
            {
                XmlDocument doc 
    = new XmlDocument();
                doc.LoadXml(viewXml);

                XmlNodeList nodes 
    = doc.DocumentElement.GetElementsByTagName("OrderBy");

                
    if (nodes == null || nodes.Count == 0)
                    
    return "";
                
    else
                    
    return nodes[0].OuterXml;
            }

            
    /// <summary>
            
    /// 指定ID的试图是否存在
            
    /// </summary>
            
    /// <param name="views"></param>
            
    /// <param name="viewId"></param>
            
    /// <returns></returns>
            static public bool ViewExist(SPViewCollection views, Guid viewId)
            {
                
    foreach (SPView view in views)
                {
                    
    if (view.ID == viewId)
                        
    return true;
                }
                
    return false;
            }

            
    /// <summary>
            
    /// 获取按名称排序后的子文件夹列表
            
    /// </summary>
            
    /// <param name="folders"></param>
            
    /// <returns></returns>
            static public IList<SPFolder> GetSortedFolders(SPFolderCollection folders)
            {
                List
    <SPFolder> sortedFolders = new List<SPFolder>();

                
    foreach (SPFolder f in folders)
                {
                    
    if (f.Item != null//为非系统文件夹
                        sortedFolders.Add(f);
                }

                sortedFolders.Sort(CompareFolder);

                
    return sortedFolders;
            }

            
    static int CompareFolder(SPFolder f1, SPFolder f2)
            {
                
    return f1.Name.CompareTo(f2.Name);
            }

            
    /// <summary>
            
    /// 获取按某个字段排序后的子文件夹
            
    /// </summary>
            
    /// <param name="folders"></param>
            
    /// <param name="sortFieldName"></param>
            
    /// <returns></returns>
            static public IList<SPFolder> GetSortedFolders(SPFolderCollection folders , string sortFieldName )
            {
               
                List
    <SPFolder> sortedFolders = new List<SPFolder>();

                
    foreach (SPFolder f in folders)
                {
                    
    if( f.Item != null ) //为非系统文件夹
                        sortedFolders.Add(f);
                }

                SPFolderComparer c 
    = new SPFolderComparer(sortFieldName);

                sortedFolders.Sort(c);

                
    return sortedFolders;
            }

            
    class SPFolderComparer : IComparer<SPFolder>
            {
                
    private string _sortFieldName;
                
    public SPFolderComparer(string sortFieldName)
                {
                    _sortFieldName 
    = sortFieldName;
                }

                
    #region IComparer<SPFolder> 成员

                
    public int Compare(SPFolder x, SPFolder y)
                {
                    
    //if (IsHiddenFolder(x) || IsHiddenFolder(y)) return 0;                

                    
    if (!x.Item.Fields.ContainsField(_sortFieldName) || !y.Item.Fields.ContainsField(_sortFieldName))
                        
    return 0;

                    
    string sX = "" + x.Item[_sortFieldName];
                    
    if (sX == "")
                        sX 
    = "0";

                    
    string sY = "" + y.Item[_sortFieldName];
                    
    if (sY == "")
                        sY 
    = "0";

                    
    return Convert.ToInt32( sX ).CompareTo( Convert.ToInt32(sY) ) ;
                    
                }

                
    #endregion
            }

        }

     

    WebFolderNavigation 直接继承于Menu,用递规遍历站点的所有列表和子文件夹来创建Menu的子菜单项。考虑到了对列表和文件夹的排序支持,

    列表的排序通过站点的导航数据进行,文件夹的排序通过给文件夹添加一个"排序号"的栏来实现(给文件夹添加栏参考:WSS 扩展文件夹的属性--如何给文件夹添加扩展字段 )。

     

    Step4: SharePoint上的服务器控件可以部署到站点下的bin目录,也可以部署到GAC中,经验之谈,建议部署到GAC中,那么首先需要给项目进行签名。

     

    Step5: 把dll部署到GAC。

    可以直接把debug目录下的dll拖入C:\WINDOWS\assembly目录,也可以写个命令行脚本来自动化操作.开发的过程中要不断的把dll放入GAC,然后重启IIS应用程序池,

    所以,最好还是采用脚本来操作:在项目根目录下创建一个文本文件,改名为deployGAC.cmd , 添加以下内容:

    echo Adding assemblies to the GAC...

    "%programfiles%\Microsoft Visual Studio 8\SDK\v2.0\Bin\gacutil.exe" -if bin\Debug\CodeArt.SharePoint.WebControls.dll

    iisapp /a "SharePoint - 81" /r

    iisapp是重启应用程序池的命令,"SharePoint – 81为应用程序池的名称,请修改为自己开发环境的应用程序池名称。

     

    Step6: 利用reflector找到的dll的全名:CodeArt.SharePoint.WebControls, Version=1.0.0.0, Culture=neutral, PublicKeyToken=9a525f21aa237e5b

     

    Step7: 配置SafeControl。

    SharePoint站点页面中使用的所有服务器控件必须在应用程序的web.config中进行配置(这样做是为了安全原因,防止普通用户通过站点上传一个dll来运行)。

    打开应用程序的web.config文件(一般为C:\Inetpub\wwwroot\wss\VirtualDirectories\XXX\web.cofig),在<SafeControls>节点下添加如下配置:

    <SafeControl Assembly=" CodeArt.SharePoint.WebControls, Version=1.0.0.0, Culture=neutral, PublicKeyToken=9a525f21aa237e5b" Namespace=" CodeArt.SharePoint.WebControls " TypeName="*" Safe="True" />

     

    Step8: WebFolderNavigation应该添加进站点的母板页里。用SPD打开站点,打开要修改的母板页。首先添加dll的Register指令。在<html标签上方添加:

    <%@ Register Assembly=" CodeArt.SharePoint.WebControls, Version=1.0.0.0, Culture=neutral, PublicKeyToken=9a525f21aa237e5b" Namespace=" CodeArt.SharePoint.WebControls " TagPrefix="codeart" %>

     

    Step9: 我们修改的是导航控件,所有,需要把WebFolderNavigation放入<Sharepoint:SPNavigationManager这个服务器控件内部:

    <Sharepoint:SPNavigationManager

                    id="QuickLaunchNavigationManager"

                    runat="server"

                    QuickLaunchControlId="SiteNavigation1"

                    ContainedControl="QuickLaunch"

                    EnableViewState="false">

        < codeart: WebFolderNavigation ID="WebFolderNavigation1" runat="server" />

    </Sharepoint:SPNavigationManager>

     

    Step10:   保存并发布母板页。

     

    Game over.

    注意:CodeArt.SharePoint.WebControls, Version=1.0.0.0, Culture=neutral, PublicKeyToken=9a525f21aa237e5b中的PublicKeyToken值请用自己dll的值。

    2009年5月31日 9:28