汤尼

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::

需求:

在公司使用SharePoint的过程中,常常有这样的需求,要为一个Document Library或者List中的某一个Item进行打分,投票,根据投票高低来作决策。 比如优秀员工的评比,用户可以直接在页面上点击投票按钮,并得到当前的投票状态。

现状:

在CodePlex上找了一个现成的Content  type(HighLight), 安装使用后,发现普通用户不太会使用,而且投票页面没有直接的结果显示,不能完全满足用户的需求,所以想自己开发一个custom field,让普通用户可以象添加一般的field一样添加,并且容易使用。

开发:

要实现投票的功能,需要开发2个相关联的custom field。一个负责记录当前所有已投票的用户的信息,这样防止用户多次点击后重复投票,我们称这个field为voting field。另一个field负责计数,显示当前总共的投票数,称为Voting Result field。可能有人要问,为什么不把这两个合而为一呢? 这里主要考虑到排序的问题,因为要记录用户投票信息的字段的type不能是text的,因为text类型有255的长度限制,只能是note型,而note型是不支持在view的页面中排序的。

下面详细介绍具体的开发

1 Voting Field

首先是字段类ItemVoting的代码

 

代码
  1  public class ItemVoting : SPFieldText
  2     {
  3         private static string[] CustomPropertyNames = new string[] { "FieldNameProperty" };
  4 
  5         public ItemVoting(SPFieldCollection fields, string fieldName)
  6             : base(fields, fieldName)
  7         {
  8             InitProperties();
  9             this.ShowInNewForm = true;
 10             this.ShowInEditForm = true;
 11             
 12         }
 13 
 14         public ItemVoting(SPFieldCollection fields, string typeName, string displayName)
 15             : base(fields, typeName, displayName)
 16         {
 17             InitProperties();
 18             this.ShowInNewForm = true;
 19             this.ShowInEditForm = true;
 20         }
 21 
 22         #region Property storage and bug workarounds - do not edit
 23 
 24         /// <summary>
 25         /// Indicates that the field is being created rather than edited. This is necessary to 
 26         /// work around some bugs in field creation.
 27         /// </summary>
 28         public bool IsNew
 29         {
 30             get { return _IsNew; }
 31             set { _IsNew = value; }
 32         }
 33         private bool _IsNew = false;
 34 
 35         /// <summary>
 36         /// Backing fields for custom properties. Using a dictionary to make it easier to abstract
 37         /// details of working around SharePoint bugs.
 38         /// </summary>
 39         private Dictionary<stringstring> CustomProperties = new Dictionary<stringstring>();
 40 
 41         /// <summary>
 42         /// Static store to transfer custom properties between instances. This is needed to allow
 43         /// correct saving of custom properties when a field is created - the custom property 
 44         /// implementation is not used by any out of box SharePoint features so is really buggy.
 45         /// </summary>
 46         private static Dictionary<stringstring> CustomPropertiesForNewFields = new Dictionary<stringstring>();
 47 
 48         /// <summary>
 49         /// Initialise backing fields from base property store
 50         /// </summary>
 51         private void InitProperties()
 52         {
 53             foreach (string propertyName in CustomPropertyNames)
 54             {
 55                 CustomProperties[propertyName] = base.GetCustomProperty(propertyName) + "";
 56             }
 57         }
 58 
 59         /// <summary>
 60         /// Take properties from either the backing fields or the static store and 
 61         /// put them in the base property store
 62         /// </summary>
 63         private void SaveProperties()
 64         {
 65             foreach (string propertyName in CustomPropertyNames)
 66             {
 67                 base.SetCustomProperty(propertyName, GetCustomProperty(propertyName));
 68             }
 69         }
 70 
 71         /// <summary>
 72         /// Get an identifier for the field being added/edited that will be unique even if
 73         /// another user is editing a property of the same name.
 74         /// </summary>
 75         /// <param name="propertyName"></param>
 76         /// <returns></returns>
 77         private string GetCacheKey(string propertyName)
 78         {
 79             return SPContext.Current.GetHashCode() + "_" + (ParentList == null ? "SITE" : ParentList.ID.ToString()) + "_" + propertyName;
 80         }
 81 
 82         /// <summary>
 83         /// Replace the buggy base implementation of SetCustomProperty
 84         /// </summary>
 85         /// <param name="propertyName"></param>
 86         /// <param name="propertyValue"></param>
 87         new public void SetCustomProperty(string propertyName, object propertyValue)
 88         {
 89             if (IsNew)
 90             {
 91                 // field is being added - need to put property in cache
 92                 CustomPropertiesForNewFields[GetCacheKey(propertyName)] = propertyValue + "";
 93             }
 94 
 95             CustomProperties[propertyName] = propertyValue + "";
 96         }
 97 
 98         /// <summary>
 99         /// Replace the buggy base implementation of GetCustomProperty
100         /// </summary>
101         /// <param name="propertyName"></param>
102         /// <param name="propertyValue"></param>
103         new public object GetCustomProperty(string propertyName)
104         {
105             if (!IsNew && CustomPropertiesForNewFields.ContainsKey(GetCacheKey(propertyName)))
106             {
107                 string s = CustomPropertiesForNewFields[GetCacheKey(propertyName)];
108                 CustomPropertiesForNewFields.Remove(GetCacheKey(propertyName));
109                 CustomProperties[propertyName] = s;
110                 return s;
111             }
112             else
113             {
114                 return CustomProperties[propertyName];
115             }
116         }
117 
118         /// <summary>
119         /// Called when a field is created. Without this, update is not called and custom properties
120         /// are not saved.
121         /// </summary>
122         /// <param name="op"></param>
123         public override void OnAdded(SPAddFieldOptions op)
124         {
125             base.OnAdded(op);
126             Update();  
127         }
128 
129         #endregion
130 
131 
132         public override BaseFieldControl FieldRenderingControl
133         {
134             get
135             {
136                 BaseFieldControl fieldControl = new ItemVotingControl(this);
137                 fieldControl.FieldName = InternalName;
138                 if(String.IsNullOrEmpty(fieldControl.ItemFieldValue as string))
139                 {
140                     fieldControl.ItemFieldValue = "<Root><Item><CurrentFieldName Type=\"String\">[" + fieldControl.FieldName + "]</CurrentFieldName><Account Type=\"String\">ads\\mossadmin</Account></Item></Root>";
141                 }
142                 return fieldControl;
143             }
144         }
145 
146         public override void Update()
147         {
148             SaveProperties();
149             base.Update();
150         }
151 
152         public string FieldNameProperty
153         {
154             get { return this.GetCustomProperty("HiddenFieldName"+ ""; }
155             set { this.SetCustomProperty("HiddenFieldName", value); }
156         }
157 
158 
159 
160     }

 

 为了能够在view页面得到当前字段的internal name(需要提供给投票处理页面voting.aspx),我们为字段赋的初始值中包含了当前field的internal name( fieldControl.ItemFieldValue = "<Root><Item><CurrentFieldName Type=\"String\">[" + fieldControl.FieldName + "]</CurrentFieldName><Account Type=\"String\">ads\\mossadmin</Account></Item></Root>";),为了在页面中,能够使得我们开发的2个自定义字段发生联系,我们在自定义字段的xml文件中为这个字段中添加了一个field property-- HiddenFieldName

接下来是呈现类代码:

 

代码
 public class ItemVotingControl : BaseFieldControl
    {
        
private ItemVoting field;
        
private List<Voter> voterList;
        
private LiteralControl ltcNumber;
        
private bool isVoted = false;
        
public ItemVotingControl(ItemVoting parentField)
        {
            
this.field = parentField;
        }

        
protected override void OnInit(EventArgs e)
        {
            
base.OnInit(e);
            
if (this.ListItemFieldValue != null)
            {
                
this.voterList = SerializeUtility.Deserialize(this.ListItemFieldValue.ToString());
            }
            
else
            {
                
this.voterList = new List<Voter>();
            }
        }

        
protected override void CreateChildControls()
        {
            ltcNumber 
= new LiteralControl();
            
this.Controls.Add(ltcNumber);
        }

        
public override void UpdateFieldValueInItem()
        {
           
        }

        
protected override void RenderFieldForDisplay(HtmlTextWriter output)
        {
            
int countValue = voterList.Count > 0 ? voterList.Count - 1 : voterList.Count;
            output.Write(countValue.ToString());
        }

        
protected override void Render(HtmlTextWriter output)
        {
            RenderFieldForDisplay(output);
        }
    }

呈现控件取出了序列化后的投票结果,并反序列化,然后显示. 注意这里的显示只是指在New.aspx,edit.aspx,display.aspx这三个页面的显示,当然用户要求直接在view的页面上投票,所以我们要提供字段在view页面的现示实现。于是我们修改了field_字段.xml文件中的<RenderPattern Name="DisplayPattern">节。

下面是完整的field_字段.xml 文件:

 

代码
 1 <?xml version="1.0" encoding="utf-8" ?>
 2 <FieldTypes>
 3   <FieldType>
 4     <Field Name="TypeName">ItemVoting</Field>
 5     <Field Name="ParentType">Note</Field>
 6     <Field Name="TypeDisplayName">Item Voting</Field>
 7     <Field Name="TypeShortDescription">Item Voting</Field>
 8     <Field Name="UserCreatable">TRUE</Field>
 9     <Field Name="Sortable">TRUE</Field>
10     <Field Name="AllowBaseTypeRendering">TRUE</Field>
11     <Field Name="Filterable">TRUE</Field>
12     <Field Name="FieldTypeClass">AECSharePoint.Field.Voting.ItemVoting, AECSharePoint.Field.Voting, Version=1.0.0.0, Culture=neutral, PublicKeyToken=c8afc6fd77dac842</Field>
13     <PropertySchema>
14       <Fields>
15         <Field Hidden="FALSE" Name="HiddenFieldName"
16         DisplayName="My Custom Property"
17         Type="Text">
18         </Field>
19       </Fields>
20       <Fields></Fields>
21     </PropertySchema>
22     <RenderPattern Name="DisplayPattern">
23       <HTML>
24         <![CDATA[
25         <a id='linkVoting' href="javascript:window.location= SetLocation(']]></HTML>
26       <ListProperty Select="Name"/>
27       <HTML>
28         <![CDATA[',']]>
29       </HTML>
30       <ListProperty Select="Title"/>
31       <HTML>
32         <![CDATA[',']]>
33       </HTML>
34       <Column Name="ID"/>
35       <HTML>
36         <![CDATA[',']]>
37       </HTML>
38         <ListProperty Select="DefaultViewUrl"/>
39       <HTML>
40         <![CDATA[',']]>
41       </HTML>
42       <Column HTMLEncode="TRUE"/>
43       <HTML>
44         <![CDATA[');"><img onerror="SetLinkDisplayContent(']]>
45       </HTML>
46       <Column HTMLEncode="TRUE"/>
47       <HTML>
48         <![CDATA[',this);" border=0 src="#"><div align="center" id="divCount" style="clear:left;display:inline;"></div></a>]]>
49       </HTML>
50       <HTML>
51         <![CDATA[
52         <script>
53         function SetLocation(listName,listTitle, itemID, listViewUrl, fieldValue)
54         {
55             var xmlDoc = new ActiveXObject("Microsoft.XMLDOM");
56             xmlDoc.loadXML(fieldValue);
57             var fieldNameNode = xmlDoc.documentElement.selectSingleNode("//Item/CurrentFieldName");
58             var fieldName = fieldNameNode.text;
59             var start = fieldName.indexOf("[");
60             var end = fieldName.indexOf("]");
61             
62             fieldName = fieldName.substring(start+1, end);
63  
64             var queryStr = "?listName=" + listName + "&amp;itemID=" + itemID + "&amp;fieldName=" + fieldName + "&amp;Source=" + window.location;
65             var currentSiteURL = "http://" + document.location.host;
66 
67             var endIndex = listViewUrl.indexOf("/Lists/");
68             if(endIndex == -1)
69             {
70                 endIndex = listViewUrl.indexOf("/" + listTitle + "/")
71             }
72             var subUrl = listViewUrl.substring(0,endIndex);
73             subUrl += "/_layouts/AECSharePoint/Voting.aspx";
74             currentSiteURL += subUrl + queryStr;
75             return currentSiteURL;   
76         }
77         
78         function SetLinkDisplayContent(fieldValue,o)
79         {
80 
81             o.src = "/_layouts/AECSharePoint/voting.gif";
82         }
83 
84         </script>
85         ]]>
86       </HTML>
87     </RenderPattern>
88   </FieldType>
89 </FieldTypes>
90 
91 

 

在 <RenderPattern Name="DisplayPattern"> 中我们使得字段在view页面显示为一个图标,点击图标后跳转到我们开发的一个application page,同时为这个page传输必要的listid,itemid等信息,此页面处理此次投票,保存投票结果作为字段的值。

下面是我们放在Template/Layout/下的自定义application page,也就是上面xml中提到的voting.aspx 代码:

 

代码
<%@ Assembly Name="Microsoft.SharePoint.ApplicationPages, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c"%>
<%@ Page Language="C#" Inherits="Microsoft.SharePoint.WebControls.LayoutsPageBase" MasterPageFile="~/_layouts/application.master"%>
<%@ Import Namespace="Microsoft.SharePoint" %>
<%@ Import Namespace="Microsoft.SharePoint.WebControls" %>
<%@ Import Namespace="System.Xml" %>
<%@ Import Namespace="System.Reflection" %>
<%@ Import Namespace="System.Collections.Generic" %>
<%@ Import Namespace="System.Diagnostics" %>

<script runat="server">
    
public Dictionary<stringobject> initialParam = null;
    
private List<Voter> voterList;
    
private bool isVoted = false;
    
class Voter
    {
        
private string _currentFieldName;
        
private string _account;

        
public string CurrentFieldName
        {
            
get
            {
                
return this._currentFieldName;
            }
            
set
            {
                
this._currentFieldName = value;
            }
        }

        
public string Account
        {
            
get
            {
                
return this._account;
            }
            
set
            {
                
this._account = value;
            }
        }
    }
    
    
#region //Serialize&deserialize the voting result
    
class SerializeUtility
    {
        
public static string Serialize(List<Voter> GenericList)
        {
            XmlDocument result 
= new XmlDocument();
            result.LoadXml(
"<Root></Root>");
            
foreach (Voter obj in GenericList)
            {
                XmlElement Item 
= result.CreateElement("Item");
                PropertyInfo[] properties 
= obj.GetType().GetProperties();
                
foreach (PropertyInfo property in properties)
                {
                    
if (property.GetValue(obj, null!= null)
                    {
                        XmlElement element 
= result.CreateElement(property.Name);
                        element.SetAttribute(
"Type", property.PropertyType.Name);
                        element.InnerText 
= property.GetValue(obj, null).ToString();
                        Item.AppendChild(element);
                    }
                }
                result.DocumentElement.AppendChild(Item);
            }
            
return result.InnerXml;
        }

        
public static List<Voter> Deserialize(string XmlStr)
        {
            List
<Voter> result = new List<Voter>();
            XmlDocument XmlDoc 
= new XmlDocument();
            XmlDoc.LoadXml(XmlStr);
            
foreach (XmlNode ItemNode in XmlDoc.GetElementsByTagName("Root").Item(0).ChildNodes)
            {
                Voter item 
= Activator.CreateInstance<Voter>();
                PropertyInfo[] properties 
= typeof(Voter).GetProperties();
                
foreach (XmlNode propertyNode in ItemNode.ChildNodes)
                {
                    
string name = propertyNode.Name;
                    
string type = propertyNode.Attributes["Type"].Value;
                    
string value = propertyNode.InnerXml;
                    
foreach (PropertyInfo property in properties)
                    {
                        
if (name == property.Name)
                        {
                            property.SetValue(item, Convert.ChangeType(value, property.PropertyType), 
null);
                        }
                    }
                }
                result.Add(item);
            }
            
return result;
        }
    }
    
#endregion
    
    
class VotingBiz
    {
        
internal Voter GetCurrentVoter(string fieldName, string account)
        {
            Voter currentVoter 
= new Voter();
            currentVoter.Account 
= account;
            currentVoter.CurrentFieldName 
= string.Empty;
            
return currentVoter;
        }

        
internal void UpdateListFieldValueWithElevatedPrivileges(Guid listID, int itemID, Dictionary<stringobject> dicFieldValue)
        {
            
if (SPContext.Current == null)
                
return;
            SPSecurity.RunWithElevatedPrivileges(
delegate()
            {
                
using (SPSite site = new SPSite(SPContext.Current.Site.ID))
                {
                    
using (SPWeb web = site.OpenWeb(SPContext.Current.Web.ID))
                    {
                        web.AllowUnsafeUpdates 
= true;
                        SPList list 
= web.Lists[listID];
                        SPListItem item 
= list.GetItemById(itemID);
                        
if (item == null)
                        {
                            
return;
                        }
                        
else
                        {
                            
foreach(KeyValuePair<stringobject> singleItem in dicFieldValue)
                            {
                                item[singleItem.Key] 
= singleItem.Value;
                            }
                            item.SystemUpdate(
false);
                        }
                    }
                }

            });
        }

        
internal bool CheckIsItemVoted(object itemValue, string fieldName, string account)
        {
            VotingBiz voteMgnt 
= new VotingBiz();
            List
<Voter> voterList = null;
            Voter currentVoter 
= voteMgnt.GetCurrentVoter(fieldName, account);
            
if (itemValue == null)
            {
                
return false;
            }
            
else
            {
                voterList 
= SerializeUtility.Deserialize(itemValue.ToString());
                
//if (itemValue.ToString().IndexOf(currentVoter.Account) != -1)
                
//{
                
//    return true;
                
//}
                
//else
                
//{
                
//    return false;
                
//}
                if (!voterList.Exists(delegate(Voter v) { return v.Account == currentVoter.Account; }))
                {
                    
return false;
                }
                
else
                {
                    
return true;
                }
            }
            
//if (!voterList.Exists(delegate(Voter v) { return v.Account == currentVoter.Account; }))
            
//{
            
//    return false;
            
//}
            
//else
            
//{
            
//    return true;
            
//}
        }
    }

    
protected override void OnLoad(EventArgs e)
    {
        InitialParamter();
    }
    
protected void InitialParamter()
    {
        
try
        {
            initialParam 
= new Dictionary<stringobject>();
            initialParam.Add(
"listName", Request.QueryString["listName"].ToString());
            initialParam[
"itemID"= Request.QueryString["itemID"].ToString();
            initialParam[
"fieldName"= Request.QueryString["fieldName"].ToString();
            initialParam[
"fieldValue"= GetItemValue(initialParam["fieldName"as string, initialParam["listName"as string, Int32.Parse(initialParam["itemID"as string));
        }
        
catch (Exception ex)
        {
            EventLog.WriteEntry(
"Voting Field", SPContext.Current.Web.Title + ":" + ex.Message + "--" + ex.StackTrace);
            Response.Write(
"Error happend, please contact site admin");
        }
    }
    
    
protected object GetItemValue(string fieldName, string listName, int itemId)
    {
        
using (SPSite site = new SPSite(SPContext.Current.Site.ID))
        {
            
using (SPWeb web = site.OpenWeb(SPContext.Current.Web.ID))
            {
                Guid listId 
= new Guid(listName);
                SPList list 
= web.Lists[listId];
                SPListItem item 
= list.GetItemById(itemId);
                
return item[fieldName];
            }
        }
    }

    
private string GetVotingResultFieldName(Guid listId)
    {
        
if (SPContext.Current == null)
            
return null;

        
string votingFieldName = String.Empty;
        
using (SPSite site = new SPSite(SPContext.Current.Site.ID))
        {
            
using (SPWeb web = site.OpenWeb(SPContext.Current.Web.ID))
            {
                SPList list 
= web.Lists[listId];
                
foreach (SPField field in list.Fields)
                {
                    
if (null != field.GetCustomProperty("FlagFieldNameProperty"))
                    {
                        votingFieldName 
= field.InternalName;
                        
break;
                    }
                }

            }
        }
        
return votingFieldName;
    }
    
    
    
    
protected void btnVote_Click(object sender, EventArgs e)
    {
        VotingBiz voteMgnt 
= new VotingBiz();

        
if (null != initialParam)
        {
            
if (!voteMgnt.CheckIsItemVoted(initialParam["fieldValue"], initialParam["fieldName"as string, SPContext.Current.Web.CurrentUser.ID.ToString()))
            {
                Voter currentVoter 
= voteMgnt.GetCurrentVoter(initialParam["fieldName"as string, SPContext.Current.Web.CurrentUser.ID.ToString());
                
if (initialParam["fieldValue"!= null)
                {
                    
this.voterList = SerializeUtility.Deserialize(initialParam["fieldValue"as string);
                }
                voterList.Add(currentVoter);
                Guid listId 
= new Guid(initialParam["listName"as string);
                
int itemId = Int32.Parse(initialParam["itemID"as string);
                
string fieldName = initialParam["fieldName"as string;
                
string votingResultFieldName = GetVotingResultFieldName(listId);
                Dictionary
<stringobject> fieldNameValuePairs = new Dictionary<stringobject>();
                fieldNameValuePairs[fieldName] 
= SerializeUtility.Serialize(voterList);
                
if (!String.IsNullOrEmpty(votingResultFieldName))
                {
                    fieldNameValuePairs[votingResultFieldName] 
= voterList.Count - 1;
                }
                voteMgnt.UpdateListFieldValueWithElevatedPrivileges(listId, itemId, fieldNameValuePairs);
                
this.isVoted = true;
            }
        }

        ReturnToSourcePage();

    }

    
private void ReturnToSourcePage()
    {
        
string sourceUrl = Request.QueryString["Source"].ToString();
        Response.Redirect(sourceUrl);
    }
    
    
protected void btnBack_Click(object sender, EventArgs e)
    {
        ReturnToSourcePage();
    }
</script>

<asp:Content ID="Content1" ContentPlaceHolderID="PlaceHolderPageTitleInTitleArea" runat="server">
    
<h>
        Vote Here
    
</h>

</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="PlaceHolderMain" runat="server">
    
<div>
        Are you sure to vote 
this item? <br />
    
<b>Please note that your vote would be counted only once even if you vote again!</b>
    
<br/>
    
<br/>
        
<asp:Button ID="btnVote" runat="server" Text="Vote" OnClick="btnVote_Click" class="ms-ButtonHeightWidth" Width="80px" />
        
<asp:Button ID="btnBack" runat="server" Text="Cancel" OnClick="btnBack_Click" class="ms-ButtonHeightWidth" Width="80px" />
    
</div>
</asp:Content>

 

 

下面介绍统计投票的字段voting result field

1.字段类代码

代码
  1  public class ItemVotingResult : SPFieldText
  2     {
  3         private static string[] CustomPropertyNames = new string[] { "MyCustomProperty" };
  4 
  5         public ItemVotingResult(SPFieldCollection fields, string fieldName)
  6             : base(fields, fieldName)
  7         {
  8             InitProperties();
  9         }
 10 
 11         public ItemVotingResult(SPFieldCollection fields, string typeName, string displayName)
 12             : base(fields, typeName, displayName)
 13         {
 14             InitProperties();
 15         }
 16 
 17         #region Property storage and bug workarounds - do not edit
 18 
 19         /// <summary>
 20         /// Indicates that the field is being created rather than edited. This is necessary to 
 21         /// work around some bugs in field creation.
 22         /// </summary>
 23         public bool IsNew
 24         {
 25             get { return _IsNew; }
 26             set { _IsNew = value; }
 27         }
 28         private bool _IsNew = false;
 29 
 30         /// <summary>
 31         /// Backing fields for custom properties. Using a dictionary to make it easier to abstract
 32         /// details of working around SharePoint bugs.
 33         /// </summary>
 34         private Dictionary<stringstring> CustomProperties = new Dictionary<stringstring>();
 35 
 36         /// <summary>
 37         /// Static store to transfer custom properties between instances. This is needed to allow
 38         /// correct saving of custom properties when a field is created - the custom property 
 39         /// implementation is not used by any out of box SharePoint features so is really buggy.
 40         /// </summary>
 41         private static Dictionary<stringstring> CustomPropertiesForNewFields = new Dictionary<stringstring>();
 42 
 43         /// <summary>
 44         /// Initialise backing fields from base property store
 45         /// </summary>
 46         private void InitProperties()
 47         {
 48             foreach (string propertyName in CustomPropertyNames)
 49             {
 50                 CustomProperties[propertyName] = base.GetCustomProperty(propertyName) + "";
 51             }
 52         }
 53 
 54         /// <summary>
 55         /// Take properties from either the backing fields or the static store and 
 56         /// put them in the base property store
 57         /// </summary>
 58         private void SaveProperties()
 59         {
 60             foreach (string propertyName in CustomPropertyNames)
 61             {
 62                 base.SetCustomProperty(propertyName, GetCustomProperty(propertyName));
 63             }
 64         }
 65 
 66         /// <summary>
 67         /// Get an identifier for the field being added/edited that will be unique even if
 68         /// another user is editing a property of the same name.
 69         /// </summary>
 70         /// <param name="propertyName"></param>
 71         /// <returns></returns>
 72         private string GetCacheKey(string propertyName)
 73         {
 74             return SPContext.Current.GetHashCode() + "_" + (ParentList == null ? "SITE" : ParentList.ID.ToString()) + "_" + propertyName;
 75         }
 76 
 77         /// <summary>
 78         /// Replace the buggy base implementation of SetCustomProperty
 79         /// </summary>
 80         /// <param name="propertyName"></param>
 81         /// <param name="propertyValue"></param>
 82         new public void SetCustomProperty(string propertyName, object propertyValue)
 83         {
 84             if (IsNew)
 85             {
 86                 // field is being added - need to put property in cache
 87                 CustomPropertiesForNewFields[GetCacheKey(propertyName)] = propertyValue + "";
 88             }
 89 
 90             CustomProperties[propertyName] = propertyValue + "";
 91         }
 92 
 93         /// <summary>
 94         /// Replace the buggy base implementation of GetCustomProperty
 95         /// </summary>
 96         /// <param name="propertyName"></param>
 97         /// <param name="propertyValue"></param>
 98         new public object GetCustomProperty(string propertyName)
 99         {
100             if (!IsNew && CustomPropertiesForNewFields.ContainsKey(GetCacheKey(propertyName)))
101             {
102                 string s = CustomPropertiesForNewFields[GetCacheKey(propertyName)];
103                 CustomPropertiesForNewFields.Remove(GetCacheKey(propertyName));
104                 CustomProperties[propertyName] = s;
105                 return s;
106             }
107             else
108             {
109                 return CustomProperties[propertyName];
110             }
111         }
112 
113         /// <summary>
114         /// Called when a field is created. Without this, update is not called and custom properties
115         /// are not saved.
116         /// </summary>
117         /// <param name="op"></param>
118         public override void OnAdded(SPAddFieldOptions op)
119         {
120             base.OnAdded(op);
121             Update();
122         }
123 
124         #endregion
125 
126 
127         public override BaseFieldControl FieldRenderingControl
128         {
129             get
130             {
131                 BaseFieldControl fieldControl = new ItemVotingResultControl(this);
132 
133                 fieldControl.FieldName = InternalName;
134 
135                 return fieldControl;
136             }
137         }
138 
139         public override void Update()
140         {
141             SaveProperties();
142             base.Update();
143         }
144 
145         public string MyCustomProperty
146         {
147             get { return this.GetCustomProperty("FlagFieldNameProperty"+ ""; }
148             set { this.SetCustomProperty("FlagFieldNameProperty", value); }
149         }
150 
151     }

 

为了能够在投票处理页面voting.aspx中找到此字段,并将结果保存到此字段,我们加了field property--FlagFieldNameProperty

2 字段显示类

 

代码
 public class ItemVotingResultControl : BaseFieldControl
    {
        
private ItemVotingResult field;
        
private LiteralControl lcResult = null;

        
public ItemVotingResultControl(ItemVotingResult parentField)
        {
            
this.field = parentField;

        }

        
protected override void OnInit(EventArgs e)
        {
            
base.OnInit(e);
        }

       
       
        
protected override void CreateChildControls()
        {
            
base.CreateChildControls();
            lcResult 
= new LiteralControl();
            
object currentResult = GetItemVotingResult();
            
if (null != currentResult)
            {
                XmlDocument xmlDoc 
= new XmlDocument();
                xmlDoc.LoadXml(currentResult.ToString());

                lcResult.Text 
= (xmlDoc.DocumentElement.ChildNodes.Count - 1+ "";
            }
            
else
            {
                lcResult.Text 
= "0";
            }
        }

        
public override void UpdateFieldValueInItem()
        {
            
        }

        
protected override void Render(HtmlTextWriter output)
        {
            lcResult.RenderControl(output);
        }
    }

 

3 field_VotingResult.xml

 

代码
<?xml version="1.0" encoding="utf-8" ?>
<FieldTypes>
  
<FieldType>
    
<Field Name="TypeName">ItemVotingResult</Field>
    
<Field Name="ParentType">Text</Field>
    
<Field Name="TypeDisplayName">Item Voting Result</Field>
    
<Field Name="TypeShortDescription">Item Voting Result</Field>
    
<Field Name="UserCreatable">TRUE</Field>
    
<Field Name="Sortable">TRUE</Field>
    
<Field Name="AllowBaseTypeRendering">TRUE</Field>
    
<Field Name="Filterable">TRUE</Field>
    
<Field Name="FieldTypeClass">AECSharePoint.Field.VotingResult.ItemVotingResult, AECSharePoint.Field.VotingResult, Version=1.0.0.0, Culture=neutral, PublicKeyToken=09a5c45e643a0621</Field>

    
<PropertySchema>
      
<Fields>
        
<Field Hidden="FALSE" Name="FlagFieldNameProperty"
        DisplayName
="My Custom Property"
        Type
="Text">
        
</Field>
      
</Fields>
      
<Fields></Fields>
    
</PropertySchema>
    
<RenderPattern Name="DisplayPattern">
      
<Column />
    
</RenderPattern>
  
</FieldType>
</FieldTypes>

 

这个字段主要用来现示投票结果,比较简单。

 

主要效果图:

投票页面:


 

 

点击vote后跳转到投票处理页面Voting.aspx

 

点击OK完成投票。注意同一用户投票只记录一次,这两个custom field同时支持List和Document Library。

代码和安装包如下:

代码:/Files/tonnie/Code.rar

安装包:/Files/tonnie/Deployfile.rar

欢迎分享和指正!

posted on 2010-05-10 16:47  Tonnie  阅读(2842)  评论(1编辑  收藏  举报