[SharePoint 2010] 客制化欄位類型
客戶提出了一個需求,在一個公告的清單中,有個負責人姓名及Email的欄位,希望是可以在新增時就預設帶建檔者的名稱跟Email.
這樣的需求或許有其他的方式可以解決,不過我所想到的方式是客制化一個欄位類型,在新增欄位時,可以設定要存取UserProfile中的哪個欄位.
開發環境
Win 2008 R2 + VS 2010 + SharePoint 2010
前言
客戶提出了一個需求,在一個公告的清單中,有個負責人姓名及Email的欄位,希望是可以在新增時就預設帶建檔者的名稱跟Email.
這樣的需求或許有其他的方式可以解決,不過我所想到的方式是客制化一個欄位類型,在新增欄位時,可以設定要存取UserProfile中的哪個欄位.
功能畫面如下
開始進行開發
這個專案中大致上會有下列檔案
- DefValueHelper.cs
提供一個GetProfileValue的函數,傳入propertyName後取得在UserProfile中該欄位的資料 - DefValueField.cs
繼承Microsoft.SharePoint.SPFieldText,
客製化的欄位類型基本上都是繼承自SPField,而SPField中提供了數種類型,而我們這次所要的是文字欄位所以是繼承SPFieldText
而繼承後主要要override的是FieldRenderingControl,
在這個FieldRenderingControl中,我們會建立我們所定義的FieldControl (DefValueFieldControl定義在下一個檔案中) - DefValueFieldControl.cs
主要用來render客製化的控制項,可以設定控制項在新增,編輯,顯示模式下,所要呈現的樣子.
主要繼承自BasicFieldControl,而我們所要呈現的是文字方塊,所以我們是繼承TextField,
但在這邊,我們不動態產生控制項,而是配合RenderingTemplate,使用ascx來拉出我們要顯示的控制項樣子,
然後在這裡面判斷是在新增,編輯或是顯示模式,然後呈現我們要顯示控制項範本及資料. - DefValueFieldControl.ascx
RenderingTemplate,在需求中,新增,編輯模式下,我們要顯示一個文字方塊,
在顯示的模式下,我們只需要顯示文字標籤,所以我們在這邊定義了兩個Template,分別只放Textbox跟Label. - fldtypes_DefValueField.xml
欄位類型的定義,包含顯示的名稱,客製化的屬性名稱設定及所使用的FieldType Class
首先先建立專案結構.
- 建立Empty Sharepoint Project,在這我使用DefValue_FieldType為專案名稱
- 在設定site and security level for debugging時,選擇 Deploy as a farm solution.
- 建立完成後在跟目錄下新增三支Code File檔案, 分別為DefValueField.cs, DefValueFieldControl.cs, DefValueHelper.cs
- 設定兩個SharePoint Mapper Folder,分別加入CONTROLTEMPLATES 與 XML
(這是VS2010的新功能,在vs2008+MOSS2007要開發這樣的功能,是要自己寫設定檔的.)
CONTROLTEMPLATES : {SharepointRoot} / TEMPLATE / CONTROLTEMPLATES
XML : {SharepointRoot} / TEMPLATE / XML - 在CONTROLTEMPLATES 的資料夾中新增 DefValueFieldControl.ascx
新增完ascx後,會自動產生*.ascx.cx與*.ascx.designer.cs,請直接刪除這兩個檔案.
而*.ascx中的<%@ Control Language="C#" AutoEventWireup="true"… %>需改成<%@ Control Language="C#"%> - 在XML資料夾中新增fldtypes_DefValueField.xml
- 新增下列的reference, 因為我們需要存取UserProfile
Microsoft.Office.Server.UserProfiles
Microsoft.Office.Server - [非必要,但跟後面的程式有關] 設定專案屬性
將Assembly name改為 : AJKits.SharePoint.DefValueFieldType
將Default namespace改為 : AJKits.SharePoint
到這,專案的結構差不多建好了.
開始寫程式
- DefValueHelper.cs
using System;
using Microsoft.SharePoint;
using System.Web;
using Microsoft.Office.Server.UserProfiles;
namespace AJKits.SharePoint
{
public class DefValueHelper
{
public string GetProfileValue(string propertyName)
{
string defValue = string.Empty;
if (!string.IsNullOrEmpty(propertyName))
{
string userName = HttpContext.Current.User.Identity.Name;
if (!string.IsNullOrEmpty(userName))
{ //SPServiceContext是Sharepoint 2010的新功能
UserProfileManager _mng = new UserProfileManager(SPServiceContext.Current);
if (_mng != null)
{
if (_mng.UserExists(userName))
{
UserProfile profile = _mng.GetUserProfile(userName);
if (profile != null)
{
defValue = Convert.ToString(profile[propertyName].Value);
}
}
}
}
}
return defValue;
}
}
} - DefValueField.cs
using System;
using Microsoft.SharePoint;
using Microsoft.SharePoint.WebControls;
using Microsoft.SharePoint.Security;
using System.Security.Permissions;
using AJKits.SharePoint.WebControls;
namespace AJKits.SharePoint
{
public class DefValueField : SPFieldText
{
public DefValueField(SPFieldCollection fields, string fieldName)
: base(fields, fieldName)
{
}
public DefValueField(SPFieldCollection fields, string typeName, string displayName)
: base(fields, typeName, displayName)
{
}
public override BaseFieldControl FieldRenderingControl
{
[SharePointPermission(SecurityAction.LinkDemand, ObjectModel = true)]
get
{
BaseFieldControl fieldControl = new DefValueFieldControl();
fieldControl.FieldName = this.InternalName;
return fieldControl;
}
}
}
} - DefValueFieldControl.cs
using System;
using System.Web.UI.WebControls;
using Microsoft.SharePoint.WebControls;
namespace AJKits.SharePoint.WebControls
{
public class DefValueFieldControl : TextField
{
protected Label DefValueForDisplay;
//取得Template Name,在顯示模式下,回傳DefValueFieldControlForDisplay,其它模式下回傳DefValueFieldControl
// DefValueFieldControlForDisplay與DefValueFieldControl為ascx中的template id
protected override string DefaultTemplateName
{
get
{
if (this.ControlMode == SPControlMode.Display)
{
return "DefValueFieldControlForDisplay";
}
else
{
return "DefValueFieldControl";
}
}
}
protected override void CreateChildControls()
{
if (this.Field != null)
{
base.CreateChildControls();
this.textBox = (TextBox)TemplateContainer.FindControl("TextField");
this.DefValueForDisplay = (Label)TemplateContainer.FindControl("DefValueForDisplay");
if (this.ControlMode != SPControlMode.Display)
{
if (!this.Page.IsPostBack)
{
if (this.ControlMode == SPControlMode.New)
{
//新增模式,取得自訂的propertyName(定義在xml中),在透過DefValueHelper取得UserProfile資料
string propertyName = (String)Field.GetCustomProperty("DefaultValueName");
DefValueHelper helper = new DefValueHelper();
textBox.Text = helper.GetProfileValue(propertyName);
}
}
}
else // 顯示模式
{
// 顯示所儲存的資料
this.DefValueForDisplay.Text = (String)this.ItemFieldValue;
}
}
}
public override object Value
{
get
{
EnsureChildControls();
return base.Value;
}
set
{
EnsureChildControls();
base.Value = (String)value;
}
}
}
} - CONTROLTEMPLATES \ DefValueFieldControl.ascx
<%@ Assembly Name="$SharePoint.Project.AssemblyFullName$" %>
<%@ Assembly Name="Microsoft.Web.CommandUI, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<%@ Register Tagprefix="SharePoint" Namespace="Microsoft.SharePoint.WebControls" Assembly="Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<%@ Register Tagprefix="Utilities" Namespace="Microsoft.SharePoint.Utilities" Assembly="Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<%@ Register Tagprefix="asp" Namespace="System.Web.UI" Assembly="System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" %>
<%@ Import Namespace="Microsoft.SharePoint" %>
<%@ Register Tagprefix="WebPartPages" Namespace="Microsoft.SharePoint.WebPartPages" Assembly="Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<%@ Control Language="C#" %>
<SharePoint:RenderingTemplate ID="DefValueFieldControl" runat="server">
<Template>
<asp:TextBox ID="TextField" runat="server" />
</Template>
</SharePoint:RenderingTemplate>
<SharePoint:RenderingTemplate ID="DefValueFieldControlForDisplay" runat="server">
<Template>
<asp:Label ID="DefValueForDisplay" runat="server" />
</Template>
</SharePoint:RenderingTemplate> - XML \ fldtypes_DefValueField.xml
FieldTypeClass需要將這個專案編譯後,在透過取得Assembly Name的工具取得,
所以上面幾個程式檔案寫好後,先Build完這個專案,然後就可以夠過GetAssemblyName工具取得FieldTypeClass的內容
但GetAssemblyName只會取得AJKits.SharePoint.DefValueFieldType, Version=1.0.0.0, Culture=neutral, PublicKeyToken=1fda5a8d8aef5781
最前面的AJKits.SharePoint.DefValueField (ClassName),需要自己在設定,讓SharePoint知道這個FieldType是使用哪個Class
<?xml version="1.0" encoding="utf-8" ?>
<FieldTypes>
<FieldType>
<Field Name="TypeName">DefValue</Field>
<Field Name="ParentType">Text</Field>
<Field Name="TypeDisplayName">UserProfileData</Field>
<Field Name="TypeShortDescription">Text field with default value from user profile field</Field>
<Field Name="UserCreatable">TRUE</Field>
<Field Name="ShowOnListCreate">TRUE</Field>
<Field Name="ShowOnSurveyCreate">TRUE</Field>
<Field Name="ShowOnDocumentLibraryCreate">TRUE</Field>
<Field Name="ShowOnColumnTemplateCreate">TRUE</Field>
<Field Name="FieldTypeClass">AJKits.SharePoint.DefValueField, AJKits.SharePoint.DefValueFieldType, Version=1.0.0.0, Culture=neutral, PublicKeyToken=1fda5a8d8aef5781</Field>
<PropertySchema>
<Fields>
<Field Name="DefaultValueName" DisplayName="Property Name" MaxLength="50" DisplaySize="25" Type="Text">
<Default>PreferredName</Default>
</Field>
</Fields>
</PropertySchema>
</FieldType>
</FieldTypes>
到這,專案跟程式就寫好了.
佈署測試
再來點選專案按右鍵選擇[Deploy],就會開始編譯並佈署到建立專案時所設定的網站了,
然後開啟該網站,建一個新的清單,新增欄位,就可以看到這個新的欄位類型了.
只要設定對的propertyName,就可以取得UserProfile中的欄位資料了.
預設是PreferredName,其它的欄位名稱可以參考後面這篇
參考資料
How to: Create a Custom Field Type
Walkthrough: Creating a Custom Field Type
How to: Create a Tool to Get the Full Name of an Assembly
原始碼 : DefValue_FieldType.zip
[update:2011/03/16] 更新DefValueFieldControl.cs及原始碼