|
需求:
在公司使用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<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
接下来是呈现类代码:
代码
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 + "&itemID=" + itemID + "&fieldName=" + fieldName + "&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[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.字段类代码
代码
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 字段显示类
代码
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
欢迎分享和指正!
|
|