jmton 发表于 2015-9-25 07:26:26

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

  需求:
  在公司使用SharePoint的过程中,常常有这样的需求,要为一个Document Library或者List中的某一个Item进行打分,投票,根据投票高低来作决策。 比如优秀员工的评比,用户可以直接在页面上点击投票按钮,并得到当前的投票状态。
  现状:
  在CodePlex上找了一个现成的Contenttype(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的代码
  

代码

1public 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 = 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 = propertyValue + "";
93             }
94
95             CustomProperties = 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;
108               CustomPropertiesForNewFields.Remove(GetCacheKey(propertyName));
109               CustomProperties = s;
110               return s;
111             }
112             else
113             {
114               return CustomProperties;
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         <!]>
29       </HTML>
30       <ListProperty Select="Title"/>
31       <HTML>
32         <!]>
33       </HTML>
34       <Column Name="ID"/>
35       <HTML>
36         <!]>
37       </HTML>
38         <ListProperty Select="DefaultViewUrl"/>
39       <HTML>
40         <!]>
41       </HTML>
42       <Column HTMLEncode="TRUE"/>
43       <HTML>
44         <!]>
45       </HTML>
46       <Column HTMLEncode="TRUE"/>
47       <HTML>
48         <!]>
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<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;
                        SPListItem item = list.GetItemById(itemID);
                        if (item == null)
                        {
                            return;
                        }
                        else
                        {
                            foreach(KeyValuePair<string, object> singleItem in dicFieldValue)
                            {
                              item = 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;
                SPListItem item = list.GetItemById(itemId);
                return item;
            }
      }
    }
    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;
                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 = SerializeUtility.Serialize(voterList);
                if (!String.IsNullOrEmpty(votingResultFieldName))
                {
                  fieldNameValuePairs = 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.字段类代码
  

代码

1public 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 = 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 = propertyValue + "";
88             }
89
90             CustomProperties = 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;
103               CustomPropertiesForNewFields.Remove(GetCacheKey(propertyName));
104               CustomProperties = s;
105               return s;
106             }
107             else
108             {
109               return CustomProperties;
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
  欢迎分享和指正!
页: [1]
查看完整版本: [SharePoint开发详解] 自定义字段开发: 投票字段