这段时间手头要做一个KM系统,在发表新知识文章时需要选择一个或多个维度下的知识分类。其实实现方法有很多,例如说再做一个专门用于设置知识分类的页面,让了发表完知识时或者在了表知识前让用户选择;又或者扩展ITEM的Action,弹出一个对话框来选择。但个人觉得这三种实现都似乎是强加上去,就算实现了,也会不太自然,像是个附加品。
为了让知识分类的选择能完全融入MOSS列表中,做一个自定义字段类型来显示一个棵知识分类树供用户选择最恰当不过了,碰巧上周刚好学了自定义字段类型,嗯,看来正好能派上用场。
于是我马上动工“写”(从网上的例子中拷)了几行代码,先把框架和文件建好:
字段定义:
Code
1<?xml version="1.0" encoding="utf-8" ?>
2<FieldTypes>
3 <FieldType>
4 <Field Name="TypeName">KMClassifyField</Field>
5 <Field Name="ParentType">MultiColumn</Field>
6 <Field Name="TypeDisplayName">$Resources:BingoCustomField,KMClassifyField_DisplayName;</Field>
7 <Field Name="TypeShortDescription">$Resources:BingoCustomField,KMClassifyField_ShortDescription;</Field>
8 <Field Name="UserCreatable">TRUE</Field>
9 <Field Name="ShowOnListAuthoringPages">TRUE</Field>
10 <Field Name="ShowOnDocumentLibraryAuthoringPages">TRUE</Field>
11 <Field Name="ShowOnSurveyAuthoringPages">TRUE</Field>
12 <Field Name="ShowOnColumnTemplateAuthoringPages">TRUE</Field>
13 <Field Name="FieldTypeClass">Bingosoft.SharePoint.CustomFields.KMClassifyField, Bingosoft.SharePoint.CustomFields, Version=1.0.0.0, Culture=neutral, PublicKeyToken=3425e7b29df5c0e5</Field>
14 </FieldType>
15</FieldTypes>
字段类:
Code
1using System;
2using System.Collections.Generic;
3using System.Text;
4using Microsoft.SharePoint;
5using Microsoft.SharePoint.WebControls;
6
7namespace Bingosoft.SharePoint.CustomFields
8{
9 public class KMClassifyField : SPFieldMultiColumn
10 {
11 构造函数#region 构造函数
12 public KMClassifyField(SPFieldCollection fields, string fieldName) : base(fields, fieldName)
13 { }
14
15 public KMClassifyField(SPFieldCollection fields, string typeName, string displayName) : base(fields, typeName, displayName)
16 { }
17 #endregion
18
19 public override object GetFieldValue(string value)
20 {
21 if (string.IsNullOrEmpty(value))
22 return null;
23
24 return new KMClassifyFieldValue(value);
25 }
26
27 public override BaseFieldControl FieldRenderingControl
28 {
29 get
30 {
31 BaseFieldControl fldControl = new KMClassifyFieldControl();
32 fldControl.FieldName = InternalName;
33 return fldControl;
34 }
35 }
36 }
37}
38
字段控件类:
Code
1using System;
2using System.Collections.Generic;
3using System.Text;
4using Microsoft.SharePoint.WebControls;
5using Microsoft.SharePoint;
6
7namespace Bingosoft.SharePoint.CustomFields
8{
9 public class KMClassifyFieldControl : BaseFieldControl
10 {
11 protected override string DefaultTemplateName
12 {
13 get
14 {
15 return "KMClassifySelector";
16 }
17 }
18 }
19}
字段值类:
Code
1using System;
2using System.Collections.Generic;
3using System.Text;
4using Microsoft.SharePoint;
5
6namespace Bingosoft.SharePoint.CustomFields
7{
8 public class KMClassifyFieldValue : SPFieldMultiColumnValue
9 {
10 public KMClassifyFieldValue(string value)
11 : base(value)
12 {
13 }
14 }
15}
最后当然是控件的模板文件(用户控件)
1<%@ Control Language="C#" Debug="true" %>
2<%@ Assembly Name="Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
3<%@ Register TagPrefix="SharePoint" Assembly="Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c"
4 Namespace="Microsoft.SharePoint.WebControls" %>
5<SharePoint:RenderingTemplate ID="TelephoneFieldRendering" runat="server">
6 <Template>
7 <div>
8 <div class="" style="width: 100%;">
9 Tree is here
10 </div>
11 <div class="" style="text-align: right; width: 100%;">
12 <input id="btnDispAll" type="button" value="显示全部" onclick="btnDispAll_onclick(this)" isDispAll="true" runat="server" /> <input id="btnUnselectAll"
13 type="button" value="取消选择" />
14 </div>
15 </div>
16 </Template>
17</SharePoint:RenderingTemplate>
N多文件“写”完了,习惯性地就先部署一下,看看就这么一点代码能不能跑(全部写完再跑的话,挂了都不知挂在哪了!)拷贝xml、ascx、dll,iisreset,OK!在一列表中新建一个栏看看,应该ascx的内容就会显示在我新建的栏中——挂了!结果竟然是什么都没~~NewForm.aspx中只显示了新建栏的名称,但ascx中的内容显没显示出来,问了N高手,又再三翻查了代码,搞了一个下午还是没有任何进展!(大家能看出上,上面的代码就是有问题的代码)
上图红框的就是我新加入的自定义字段
无奈之下只能把SDK翻了又翻,功夫不负有心人啊,竟然给我在查与模板文件相关的章节时翻到这么一段:
DefaultTemplateName contains the value of the ID attribute of a <RenderingTemplate> element in an .ascx file in the folder C:\program files\common files\microsoft shared\web server extensions\12\template\controltemplates.
上面意思是说字段控件类中重写的DefaultTemplateName属性的值是模板文件(ascx文件)中的RenderingTemplate控件的ID,马上打开ASCX文件看看,哦~~~,马上茅塞顿开!因为我的代码框架是从另外一个例子中拷过来的,控件的ID没有注意改掉,把模板中的代码
<SharePoint:RenderingTemplate ID="TelephoneFieldRendering" runat="server">
改成
<SharePoint:RenderingTemplate ID="KMClassifySelector" runat="server">
与字段控件类中的方法对应起来
protected override string DefaultTemplateName
{
get
{
return "KMClassifySelector";
}
}
更新文件并Reset一下IIS后,模板的内容出现了
注意:这里更新了ASCX文件也得IISReset,可能是给MOSS缓存了吧!
这说明了什么呢?首先说明了字段控件类中的DefaultTemplateName返回的必须是RenderingTemplate的ID
并不是那个ascx文件的文件名(我刚开始以为是的),但后来尝试把ascx的文件名改成其它名字,发现是没影响的,只要保持RenderingTemplate的ID与字段控件类的DefaultTemplateName返回的字符串相同就行了。这也解释了为什么改ascx文件都得reset iis 了,因为moss在render模板时并不是去找对应的模板文件,而是老早就把controltemplates下的文件读取出来了,所以再改ascx文件也不会马上有反应,必须iisreset一下!
那我们把多个RenderingTemplate写到一个ascx文件里行不?答案是肯定的。同时,当我们写多个自定义字段时,各个RenderingTemplate的ID不能有相同,否则新建与编辑页面就会抛出“发生意外错误”的信息!
综上所述,我们在“拿来主义”的指导下时,也得认真检查,个人觉得在初学的时候还是不要用Ctrl+C,Ctrl+V的方法了,宁愿慢一点,把代码照着抄一篇也是好的,起码可以检查一遍代码,对读懂代码也有很大的帮助。记得以前老人家总是说“快则慢,慢则快”还是挺有道理的,像我这样浪费了一个下午的时间多不值得啊!以上是纯属个人意见啦!哈哈!