[SharePoint开发详解] 自定义字段开发: 投票字段

需求:

在公司使用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的代码

 

ExpandedBlockStart.gif 代码
  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 < string string >  CustomProperties  =   new  Dictionary < string string > ();
 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 < string string >  CustomPropertiesForNewFields  =   new  Dictionary < string string > ();
 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

接下来是呈现类代码:

 

ExpandedBlockStart.gif 代码
  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 文件:

 

ExpandedBlockStart.gif 代码
 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 οnerrοr="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 代码:

 

ExpandedBlockStart.gif 代码
<% @ 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 < string object >  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 < string object >  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 < string object >  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 < string object > ();
            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
< string object >  fieldNameValuePairs  =   new  Dictionary < string object > ();
                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.字段类代码

ExpandedBlockStart.gif 代码
  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 < string string >  CustomProperties  =   new  Dictionary < string string > ();
 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 < string string >  CustomPropertiesForNewFields  =   new  Dictionary < string string > ();
 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 字段显示类

 

ExpandedBlockStart.gif 代码
  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

 

ExpandedBlockStart.gif 代码
<? 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

欢迎分享和指正!

转载于:https://www.cnblogs.com/tonnie/archive/2010/05/10/voting.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值