RSS 2.0 Feed

Wednesday, October 08, 2008

最近的一个SharePoint项目要求不能使用后台代码,所以为了与SharePoint内容进行交互,就得使用AJAX通过内置的web service去访问和修改SharePoint数据。

对于我这种学SharePoint比学asp.net早的人来说,用javascript去调用web service并不是一件容易的事,虽然在asmx页面中有关于发送和接收包的结构,但是很多地方都语焉不详,而且平时即使用web service,也是直接在vs里直接添加,用面向对象的方式去调用,顶多操作一些xml,对其内部的通讯结构和内容并不了解。

为了应对这种需求,特意在服务器装了sniffer pro去侦听web service数据的内容,前面都很顺利,读取用户配置文件、读取列表内容一切正常,但是到修改的时候就碰到了问题,包的数据内容与sniffer截获到的完全一致,但就是调用不成功。鼓捣了半天发现是在http header中漏掉了SOAPAction这个属性,加上之后就一切正常了。

其实这个SOAPAction在asmx的页面中也写到了,不过之前一直只注意数据,没有注意header;在sniffer中也截获到了,不过也没有注意到http header……看起来要通过web service向sharepoint里写内容的话,SOAPAction这个header是必不可少的,有点像FormDigest控件对于普通web page的意义。

等项目搞完了考虑把操作sharepoint数据的这个javascript库公开出来,嗯嗯。

ps. jQuery真是好啊真是好,解决了很多头疼的跨浏览器问题。

ps & ps. Aptana真是好啊真是好,见过的最好用的javascript编辑器。

posted @ | Feedback (0) | Filed Under [ SharePoint ]

Wednesday, September 10, 2008

u2u的创建者之一,smartpart的作者之一。讲课时心脏病突发……

posted @ | Feedback (0) | Filed Under [ SharePoint ]

Thursday, August 28, 2008

这个估计是最常用的.net工具,Lutz Roeder同学终于把它转交给Red Gate Software去开发了……这个东西居然有8年多了。

After more than eight years of working on .NET Reflector, I have decided it is time to move on and explore some new opportunities.

I have reached an agreement to have Red Gate Software continue the development of .NET Reflector. Red Gate has a lot of experience creating development tools for both .NET and SQL Server. They have the resources necessary to work on new features, and Reflector fits nicely with other .NET tools the company offers.

Red Gate will continue to provide the free community version and is looking for your feedback and ideas for future versions.

For news and updates on Reflector, sign up for the .NET Developer’s Newsletter from Red Gate. To find out more about the agreement, see the interview on Simple Talk.

posted @ | Feedback (0) | Filed Under [ C#/ASP.Net ]

Wednesday, August 27, 2008

最近有个需求,将不同的内容类型组织到同一个列表(不是文档库)中,希望能够给不同的内容类型显示不同的图标。不过SharePoint内容类型似乎没有关于图标的设置,翻了ContentType的SchemaXml和若干个xml配置文件都没找到相关的办法。

今天突然想到了计算字段,猜测大概能做到这一点,不过计算字段只能显示单行文本、数值、是/否等几种固定类型,不能显示html内容,我觉得可以通过修改默认的计算字段配置文件来达到这一目的。上网搜了一下,果然找到:Enabling HTML and/or Images in a SharePoint List using a calculated field

大致的方法就是控制计算字段在显示的时候的html编码,在FLDTYPES.XML中我们可以看到默认是这个样子的:

1 <Default> 2 <Column HTMLEncode="TRUE" AutoHyperLink="TRUE" AutoNewLine="TRUE"/> 3 </Default>

也就是说对于单行文本的显示方式,都是加上了HTML编码的,自然我们可以改掉这个地方,但是为了不影响其他计算字段的显示,可以用一些特定标记来判断,比如改成这样:

1 <IfSubString> 2 <Expr1><![CDATA[<custom/>]]></Expr1> 3 <Expr2><Column/></Expr2> 4 <Then> 5 <HTML><Column/></HTML> 6 </Then> 7 <Else> 8 <Column HTMLEncode="TRUE" AutoHyperLink="TRUE" AutoNewLine="TRUE"/> 9 </Else> 10 </IfSubString>

这段的意思是:如果计算字段的值包含“<custom/>”(这不是一个html标签,所以页面上不会显示),那么就不编码,否则对内容进行html编码。

于是,就可以在列表中创建一个计算字段栏Icon,它的公式设置成:

1 =IF([内容类型]="类型A", 2 "<custom/><img src='/_layouts/images/img1.gif'/>", 3 "<custom/><img src='/_layouts/images/img2.gif'/>")

要是支持SWITCH就更好了……

posted @ | Feedback (0) | Filed Under [ SharePoint ]

Tuesday, August 26, 2008

这里的表单指的是列表默认的新建界面和编辑界面,在点击“确定”之后实际上是可以触发一段我们自定义的代码的,比如跳转页面、做一些其他操作等事情。(虽然跳转页面可以通过url中的Source来做,但是我们往往需要跳转时url加上当前列表条目的ID,不过新建页面中是拿不到条目ID的……)

添加表单事件的方法很容易,不过没有见到网上有任何文章说这件事 -.-

在SPFormContext中使用OnSaveHandler属性就可以挂载一个EventHandler了,所以我们可以在表单页面中加入如下代码(通过WebPart或者自定义字段):

1 protected override void OnInit(EventArgs e) 2 { 3 base.OnInit(e); 4 // add save handler 5 if (SPContext.Current.FormContext.FormMode == SPControlMode.New) 6 SPContext.Current.FormContext.OnSaveHandler += new EventHandler(MyHandler); 7 }

通过Reflector,我们可以看到保存列表条目的那个确定按钮“SaveButton”在保存时所做的操作,如果当前表单中有SaveHandler的话,则不会自动保存该条目。换句话说,我们需要在代码里面自动做这件事,不过也很容易,利用SaveButton的静态方法SaveItem:

1 protected void MyHandler(object sender, EventArgs e) 2 { 3 string checkInComment = Page.Request.QueryString["CheckInComment"]; 4 if (checkInComment == null) checkInComment = ""; 5 SaveButton.SaveItem(SPContext.Current, false, checkInComment); 6 7 // do custom actions, now we can get the item id! 8 if (SPContext.Current.FormContext.FormMode == SPControlMode.New) 9 Page.Redirect("some url.aspx?ID=" + SPContext.Current.ListItem.ID.ToString(), true); 10 }

通过在自定义字段中使用,可以用这种方法实现一些功能(在自定义字段控件中可以直接用this.ControlMode代替FormMode)。

不过这种方法有一个缺陷,就是在默认的新建、编辑页面中虽然可以正常使用,但是在DataFormWebPart中(就是用SPD插入的“自定义列表表单”)中,SaveHandler无法被触发,而且当前的FormContext也有一些属性不正常(例如拿不到页面上的控件,FormMode是Invalid)……我还没有实验使用ListFormWebPart(就是原来那个表单WebPart)配合RenderTemplate的方式是不是能够行的通……

posted @ | Feedback (0) | Filed Under [ SharePoint ]

Wednesday, July 30, 2008

    我们在SharePoint上查看列表视图的时候,默认的那个Web部件(ListViewWebPart)提供了丰富且友好的功能,可以在上面进行排序、筛选等操作,每个列表条目上还有一个友好的下拉菜单。在2007中,SharePoint内置了一个类似的控件SPGridView来达到类似的效果,所以当我们需要显示一些其他数据的时候(例如来自SQL Server等),将数据绑定到SPGridView上就可以实现类似的排序和筛选效果,而不用写一行排序筛选相关的代码,下拉菜单的实现通过几行简单代码可以搞定。

    关于SPGridView网上有很多文章介绍它的用法(例如jianyi的这篇文章,其中介绍了如何通过ObjectDataSource来显示一个SharePoint风格的数据视图,并有一个比较简单的下拉菜单,也可以做排序和筛选)。但是文章的后半部分,也就是如何显示SharePoint列表数据的部分,有比较大的问题,而且根据我搜索的结果,也很少有文章提到这个问题。

    网上的一些例子在使用SharePoint列表作为数据源的时候,直接使用了SPDataSource来进行数据绑定。这个东西也是2007中新加上去的,配合SPGridView的一个控件,可以直接通过List属性绑定到一个SharePoint列表上。显示成那个样子没有问题,但是在排序和筛选的时候就有问题了。不知道那些文章的作者是否试过绑定SharePoint列表,反正在我这里用无代码方式是不能进行筛选的(排序似乎OK)。处理筛选的时候,一般介绍的方法是指定SPGridView的FilteredDataSourcePropertyName属性为“FilterExpression”、指定FilteredDataSourcePropertyFormat属性为“{1}='{0}'”,但是这种方法对于数据源为SPDataSource的SharePoint列表绑定是行不通的,因为SPDataSource并没有FilterExpression这个属性,也没有任何和筛选相关的属性,我也没找到其他解决筛选的方法。从这一点看来,我觉得SPDataSouce并不是一个完善的数据源实现,不知道在2009中会不会有改进。

    其实解决SharePoint列表数据绑定的方法也很简单,那就是先把列表数据转换成DataTable(通过SPListItemCollection的GetDataTable方法),再用ObjectDataSource作为数据源绑定到SPGridView上,这样就可以实现不写代码的排序和筛选了(不过也有一些不如用SPDataSource的地方,放到后面再说)。

    先来说筛选,关于SPGridView的筛选问题网上几乎所有的文章都提到了这一篇:Filtering with SPGridView。这篇文章主要说的内容有两点:第一、在SPGridView绑定的时候,如果希望实现筛选功能,那么在绑定时需要指定SPGridView的DataSourceID为ObjectDataSource的ID,而不能直接将DataSource指定为ObjectDataSouce;第二、默认情况下SPGridView的筛选和排序同时进行的时候会有问题(显示不合逻辑),文中给出了一种使用ViewState保存筛选条件的解决方案,在这里就不再赘述了。

    然后说说数据绑定问题,SPGridView是不支持自动生成绑定列的,所以必须把AutoGenerateColumn设成false。一般我们在写asp.net的时候,绑定数据列使用BoundField控件,在SharePoint中有一个更好的选择,那就是SPBoundField。它的使用方法和BoundField完全一致,但是它对SharePoint的数据类型(也就是栏类型)做了处理,对超链接、多选、查阅项等内容都有比较好的处理,它的底层是调用了对应SPField的GetFieldValueAsHtml方法(所以,如果你希望这个东西能很好地显示你的自定义字段类型,你最好在实现自定义字段的时候把GetFieldValueAsHtml重写)。当然,这个所谓的“比较好的处理”指的是使用SPDataSource作为数据源。当我们使用ObjectDataSource绑定用GetDataTable方法获得的DataTable时,问题就出现了:多选项不能正常显示为多选(而是;#那种内部表示)、超链接不能显示为链接(显示为“url,说明”)、人员没有链接、最不能忍受的是多行文本都不是以html形式显示的,这是因为在GetDataTable的时候,SharePoint就已经做过一次数据转换了,即使用SPBoundField绑定,也会有问题。解决方法也有,就是实现一个自己的GetDataTable……其实也不麻烦。

    最后,SPGridView是继承了GridView的,所以可以加“选择”功能,直接在最后加一列CommandField就行了。也可以通过一些trick的方法把选择按钮隐藏掉,然后实现单击一行的时候选中,比如下图:

    image

    当然,既然是继承了GridView,也可以做一些其他操作,比如加个按钮什么的。但是另一个问题又出现了,SPGridView在按钮列(或者那种下拉菜单)PostBack的时候,数据绑定失败。也有解决方案:SPGridView, SPMenuField, Grouping, Postback

posted @ | Feedback (0) | Filed Under [ SharePoint ]

Monday, July 28, 2008

    SharePoint内置了一套相对比较完整的Web Services提供给开发者,这样就可以在客户端、跨平台的程序中读取甚至修改SharePoint中的内容。不过当SharePoint网站不允许匿名访问的时候,调用Web Services自然也需要提供身份验证。

    SharePoint身份验证最常用的是Windows验证(Windows Authentication)和表单验证(Form Authentication)两种。

    Windows验证即使用Windows账号或者AD账号来进行身份验证,对于这种验证方式,在SharePoint SDK中已经给出了如何提供身份验证的方法,假设我们使用最常用的lists.asmx来获取SharePoint列表数据,添加的Web引用的命名空间是spwsList:

 

使用当前帐户身份:
1 spwsList.Lists wsLists = new spwsList.Lists(); 2 wsLists.Credentials = CredentialCache.DefaultCredential; 3 Console.WriteLine(wsLists.GetListCollection().OuterXml);

 

 

使用指定帐户:
1 spwsList.Lists wsLists = new spwsList.Lists(); 2 wsLists.Credentials = new NetworkCredential("username", "password", "domain"); 3 Console.WriteLine(wsLists.GetListCollection().OuterXml);

 

    上面的CredentialCache、NetworkCredential都是在System.Net命名空间下。

 

    表单认证是SharePoint 2007新加入的一种身份认证方式,其后台是使用.Net Framework中的Membership机制进行用户身份的识别,对于外网来说,大都是使用表单认证的方式来实现的。在使用表单认证的SharePoint网站中通过Web Service获取数据稍微麻烦一些,不过也可以通过SharePoint提供的表单认证Web Service来创建用户身份相关的Cookie。

    表单认证Web Service的地址是:http://[server]/[site]/_vti_bin/authentication.asmx

    在使用Web Service的程序中再次加入上面这个Web引用,假设其命名空间是spwsAuth,那么使用表单认证构造身份并访问数据的代码实例如下:

1 spwsAuth.Authentication auth = new spwsAuth.Authentication(); 2 auth.CookieContainer = new CookieContainer(); 3 auth.AllowAutoRedirect = true; 4 spwsAuth.LoginResult lr = auth.Login("username", "password"); 5 if (lr.ErrorCode == spwsAuth.LoginErrorCode.NoError) 6 { 7 spwsList.Lists wsList = new spwsList.Lists(); 8 wsList.CookieContainer = auth.CookieContainer; 9 XmlNode res = wsList.GetListCollection(); 10 Console.WriteLine(res.OuterXml); 11 }

posted @ | Feedback (0) |

Friday, July 25, 2008

今天遇到一个SharePoint网站,在服务器上可以访问,在服务器外访问不能(写到这里估计大部分人都能猜到是什么问题了)。于是弱智的我查看了所有IIS、Web应用程序、管理中心、SSP的相关设置,都没有找到问题所在。于是惊动了kaneboy同学,在其指导下,在IIS里新建了一个站点,扔了个hello world页面进去,依旧是里面能访问,外面访问不能。于是kaneboy同学沉思了一下,说“你防火墙关了么?”于是我就点点点了……我什么时候把服务器的防火墙打开的……

于是这篇日志就当作blog复出吧……上半年被毕业事宜折磨了半年……我过一段时间重新开始写自定义字段类型的开发,最近又有了一点心得……

posted @ | Feedback (0) | Filed Under [ SharePoint ]

Tuesday, December 04, 2007

在上一次我们已经编写好了一个带有格式验证功能的Email地址栏,那么如果需要用到这个自定义字段,必须先对其进行注册,通知SharePoint有了一个新的字段类型。其方法就是编写一个xml文件。

先来看一下这个xml文件的内容,再对其进行一一介绍:

<?xml version="1.0" encoding="utf-8" ?>
<FieldTypes>
  <FieldType>
    <Field Name="TypeName">EmailField</Field>
    <Field Name="ParentType">Text</Field>
    <Field Name="TypeDisplayName">Email Field</Field>
    <Field Name="TypeShortDescription">Email</Field>
    <Field Name="UserCreatable">TRUE</Field>
    <Field Name="ShowInListCreate">TRUE</Field>
    <Field Name="ShowInSurveyCreate">TRUE</Field>
    <Field Name="ShowInDocumentLibraryCreate">TRUE</Field>
    <Field Name="ShowInColumnTemplateCreate">TRUE</Field>
    <Field Name="FieldTypeClass">EmailField.EmailFieldField,EmailField,Version=1.0.0.0,Culture=neutral,PublicKeyToken=9f4da00116c38ec5</Field>
    <RenderPattern Name="DisplayPattern">
      <HTML><![CDATA[<a href="mailto: ]]></HTML>
      <Column HTMLEncode="TRUE" />
      <HTML><![CDATA[">]]></HTML>
      <Column HTMLEncode="TRUE" />
      <HTML><![CDATA[</a>]]></HTML>
    </RenderPattern>
  </FieldType>
</FieldTypes>

在“FieldType”一节中,定义了和该字段相关的内容,可以看到其大致分为两个部分:

第一部分是关于该字段类型的一些基本设定,比如类型名称(TypeName)、父类型名称(ParentType),

显示名称(TypeDisplayName)是指在列表设置页面中显示的名称:

image

而简短描述(TypeShortDescription)则是在创建栏页面中显示的名称:

image

是否允许用户创建(UserCreatable)指定该字段类型是否可以在创建栏的页面出现,允许用户自行创建(而不是写在列表模板的定义xml文件中)

后面一些就是设置该字段类型是否可以出现在某些列表类型中,比较重要的一个是FieldTypeClass,定义了该字段类型后台对应的类名和程序集名称,注意都要使用全名,中间用逗号分开

而第二部分是通过一系列的RenderPattern设置该字段类型的显示样式。

RenderPattern大致分为几种,HeaderPattern和FooterPattern定义了在视图页面显示该字段时的栏的头尾样式,DisplayPattern定义了字段内容的显示样式,EditPattern和NewPattern为编辑和新建时的样式,以及PreviewDisplayPattern、PreviewEditPattern和PreviewNewPattern定义了在SharePoint Designer中的样式。

可以注意到,这种样式的定义是通过一种奇怪的可以用CDATA方式搀杂html代码的形式定义的,对了,这又是CAML……其中出现的两个Column结点表示该栏的内容。

 

写到这里,我们可以发现这个xml其实可以写的很复杂,尤其是在RenderPattern的部分,因为CAML允许我们在定义显示样式的时候使用switch条件,这部分的写法很灵活,我们可以多多参考默认的那些字段是怎么写的(在fldtypes.xml中)。

此外,这个xml文件中还会涉及到自定义属性和自定义属性输入界面的控制,这个放到相应的部分再讲。

另外,非常需要值得注意的,这个xml文件必须以“fldtypes_”开头,才可以被SharePoint识别为字段类型的描述文件。

ok,现在我们把上次编译出来的dll文件拽到GAC里,把这个xml文件放到12\TEMPLATE\XML目录中,重启iis(一定要iisreset,仅回收应用程序池是不行的),然后我们就可以在创建栏的地方看到这个自定义字段类型了,并且它的表现也和我们期望的一致。

在新建界面中格式验证失败时:

image

在显示界面中:

image

并且,这个字段在编辑界面中无法看到(被我们在代码中屏蔽了)。

这两次内容综合起来,我们可以编写一个很简单的自定义字段类型了,它的功能仅仅是使用默认的那些属性、使用默认的输入界面,加上一些其他属性的初始化功能和数据验证功能,在下一次中,我会介绍一下怎样来自己编写输入界面。

(未完待续)

posted @ | Feedback (7) | Filed Under [ SharePoint ]

Thursday, November 29, 2007

从这次开始,将逐步介绍如何创建一个自定义字段类型,以及通过什么样的手段来完成我们需要的功能。

随着例子从简单到复杂,所涉及的内容也有所增长,所以大致的计划流程是这样的:字段类型、xml描述文件、输入控件、值类型、自定义属性控件、自定义属性bug的解决方案、(自定义字段间的通信),大概先分为这几期吧(看来是一个任重而道远的工程……)

那么本期先通过一个最简单的自定义字段类型的例子,来看一下如何创建自定义字段类型中的字段类。

在这个例子中,我们将编写一个Email地址的字段,它可以完成Email地址的合法性验证。

首先,自定义字段类型在SharePoint Extension for Visual Studio 2005里其实是有模板的,但是我们在创建一个项目的时候却看不到它,其实它的创建流程是这样的:

先创建一个空的SharePoint解决方案:

image

然后在新建一个Item的时候,在可选的模板中就能够看到一个“Field Control”了,选择它:

image

点确定之后,我们会发现模板为我们创建出了两个文件,xxx.Field.cs和xxx.FieldControl.cs,这两个文件分别定义了字段的类和字段的输入控件。并且自动生成了一个强命名的key,使得我们可以把编译得到的dll放到GAC中。这次主要对字段类进行介绍。

在上上次中介绍过SharePoint的内置的字段类型,每一个字段类型都有自己的类(例如单行文本对应SPFieldText),这些类全部都是SPField的子类。所以,当我们编写一个自己的字段类型的时候,也需要让这个字段类型是SPField的子类,这样才能够完成字段类型的功能。但实际上,我们往往并不需要直接继承SPField,而是找一个与我们所需要的功能最接近的字段类型继承它,这样的优点就是我们可以使用这种内置字段类型的一些特殊属性(比如单行文本中的最长字符数限制等),并且能够使用内置字段类型的默认输入界面,另一个优点就是如果要直接继承SPField,要多写一个东西(但是我忘了是什么了……汗……)。

在这个例子中,Email地址的输入和单行文本非常类似,于是我们继承SPFieldText。

好,可能有人会发现了,默认由模板创建出来的这个项目中它就是继承了SPFieldText的,在我们继续之前,不妨先来看一看这默认生成的代码中都有什么东西。

我们已经看到默认的模板创建出来了Field类和FieldControl类,并且Field类继承了SPFieldText,也就是单行文本。然后在这个Field类中,我们还可以看到如下两大部分内容:

第一部分:构造函数

public EmailFieldField(SPFieldCollection fields, string fieldName)
  : base(fields, fieldName)
{
}
        
public EmailFieldField(SPFieldCollection fields, string typeName, string displayName)
  : base(fields, typeName, displayName)
{
}

SPFieldText并不支持不带参数的默认构造函数,所以要重载这两种构造函数,而这两种构造函数也是SPField所使用的,默认情况下直接使用相同的参数调用父类的构造函数。通过Reflector我们可以看到,在SPField的这两种构造函数中都是根据参数设置了一些初始值。因此,如果需要有一些特殊的初始值要设置,我们可以放在这个构造函数中,例如如果我们希望这个Email地址栏只在新建界面中出现,而不让用户在默认界面上修改它,我们可以在构造函数中添加:

this.ShowInEditForm = false;

我们对这两个构造函数的修改一般也仅限于此类操作了。(其实我们几乎很少需要手动去调用Field系列的构造函数,在创建一个字段时我们往往使用的是SPFieldCollection的Add方法或者AddLookup方法)

在一个自定义的字段类型中,这个构造函数是字段类唯一一个必须重载的地方,其他内容都可以不写(当然如果你其他内容都不写的话,这个字段比起它的父类来说,无非就是多了一些初始值——当你需要这么做的时候,你就可以很简单地这么干来创建一种新的字段类型。。。)

第二部分:关联的控件

在默认生成的代码中,重载了SPFieldText的一个属性叫做FieldRenderingControl。顾名思义,这个只读属性是用来返回与此字段相关联的显示/输入控件的。这部分内容我们放在下下次的内容做介绍。

在这个Email地址的例子中,我们可以直接使用SPFieldText字段类型的默认输入控件(至于显示我们可以放到xml里来定义),因此我们无需重载它,把它删掉好了(同时也可以把那个xxxx.FieldControl.cs也删掉,而且它其实就是空的……)

既然是自定义字段类型,那么必然和默认的单行文本要有所区别,在这个例子中,我们所提供的额外功能就是Email地址的验证,于是我们就需要:

第三部分:数据验证

数据验证功能一般来说都是放在输入界面里做的,但是其实我们也可以把类似的功能放到字段类中(因为我们使用的是默认输入界面)。

在SPField中,有这样一个方法我们可以重载:

public override string GetValidatedString(object value)

这个方法的目的就是根据这个字段的值(object),返回一个通过验证的字符串。其主要目的第一在于验证数据,第二在于做数据串行化(Serialization),把数据值都转换成字符串。这个方法在每次提交值的时候都会执行到,所以可以用来进行数据验证。

在重载这个方法的时候,一般我们都先需要判断一下数据是否为空,然后再做真正的自定义的数据校验。如果在校验过程中发现了不合法的数据,我们需要使用一个特殊的Exception类:SPFieldValidationException。这个异常的表现形式就是我们在填错什么东西时,字段输入控件下面会出现的那行红字。

在这个例子中,我们使用正则表达式来验证Email地址,整个函数的函数体如下:

public override string GetValidatedString(object value)
{
    if (Required && (value == null || value.ToString() == ""))
    throw new SPFieldValidationException(SPResource.GetString(Strings.MissingRequiredField));

    // Validate email format
    string emailRE = @"^([\w-\.]+)@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([\w-]+\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)$";
    if (!Regex.IsMatch(value.ToString(), emailRE))
        throw new SPFieldValidationException("Invalid Email Address.");

    if (value == null)
        return string.Empty;
    else
        return value.ToString();
}

这个例子写到现在,功能已经完成了,这就是最简单的一个自定义字段类型的开发。当然到现在我们还不能用它,还需要写一个xml描述文件,放在下次介绍。

那么在这个字段类中,我们通常还可以写哪些内容呢?

第四部分:自定义属性

每个字段类型都有它自己特殊的一些属性,我们称之为自定义字段属性(比如单行文本的最大长度、数字的最大值最小值这样的)。

在SDK中编写自定义属性的方法中,并不需要在字段类中加什么内容,但由于那个bug的存在,在两种解决方案中,都需要在字段类中加上自己的属性。有关这一部分,也等到专门自定义属性的时候再说。

第五部分:获取字段值

在SPField中,获取一个字段的值通常有多种手段,完成不同的用途。例如刚刚介绍过的那个GetValidatedString。

有时为了完成其他一些用途,或者和我们其他的一些代码配合,可能需要重载这些方法,它们有:

public object GetFieldValue(string value)

——根据字符串的值获得真正的值类型(简单类型如double,复杂类型如SPFieldxxxxValue),可以把它理解为反串行化的过程。

public string GetFieldValueAsText(object value)

——根据值得到文本,与GetValidatedString方法不同,这个方法并不是总被执行,它主要还是用于显示。

public string GetFieldValueAsHtml(object value)

——和上面的方法类似,只不过是用Html的格式来显示,这两个方法已经在(0)里面提到过了。

public string GetFieldValueForEdit(object value)

——在编辑时获取一个字符串,其实这是一个有点奇怪的方法,因为后面我们在介绍输入控件的时候,一般都是用object作为Value的。难道Edit时的value会和一般的value不同么?我发现这个方法的重载是在SPFieldNumber里,当它设置为用百分比显示时,想一想编辑时填的值和真正的值有什么区别(30% vs 0.3),就可以理解它的意义了。

上面这些方法就不再一一进行介绍了,有兴趣的可以用Reflector看一看Microsoft.SharePoint.dll中,内置的那些字段类型是怎么写的,会有很大的帮助。

第六部分:其他

其实,上面的那些内容除了自定义属性之外,都是来自SPField的属性或者方法,当然我们也可以根据需要重写它的其他属性和方法。也可以写自己的……

言归正传,我们已经写了一个最简单的Email地址字段类,那么怎么样使用和部署?用什么方式对它进行描述?请看下期……

(未完待续)

posted @ | Feedback (4) |

Monday, November 26, 2007

哈哈,玩笑玩笑。话说这是我很久以来非常非常想做的一件事情,嗯嗯。

图来啦!懒得搞彩色背景了,直接灰度算了……至于字体,那当然是老徐体,嗯。

SharePoint_Sketch

posted @ | Feedback (15) | Filed Under [ SharePoint ]

Sunday, November 25, 2007

从这一节开始正式涉及到自定义字段类型的内容,嗯……不过这次还是没有代码

本次主要介绍一下自定义列表字段类型的大致内容,用途和缺点,以及大概的体系

上一次说到了SharePoint本身内置了很多种字段类型(其实还有更多,只不过我们没办法自己用罢了,都是系统默认的,比如Counter、File之类),这些字段类型虽然已经比2003时代要丰富而且功能强大了很多,但是有时依然不能满足我们的需求。例如如果你想做一个Email地址栏,你当然可以选择使用单行文本,但是一个好的Email地址输入是可以进行合法性验证的,单行文本却不行;又比如你想做更强大的输入界面,比如评分(现在SharePoint中已经有一个类似的东西了,RatingScale,但是遗憾地它只能用在调查列表中),你希望能把它做成youtube那样的效果;再比如你要做一个能够带有自动判重功能的输入栏……

自定义字段类型是一个很能激发我们想像力的东西,比如我们可以把一个字段类型当做一个按钮,它本身可以不存任何数据,只是在输入界面中根据其它字段来判断一些东西(比如我有两个时间类型的字段分别存放会议开始时间和结束时间,然后我可以做这么一个“按钮”字段,以便在输入的时候就可以判断有没有与此冲突的会议时间——这往往比使用Event Handler更加人性化一些,因为那是在提交后才判断的)。最近越来越发现自定义字段的强大,甚至有一种机制可以让不同字段之间进行交互,今天侯同学刚发现的这一点,大概试了试原理,还没用到字段类型上,等试出来了再说。

好了,言归正传,自定义字段类型主要解决的是以下问题:

  • 更复杂的输入、显示界面
  • 自定义的合法性判断检测
  • 更复杂的逻辑
  • 其他一些默认字段所无法完成的功能

举一些例子:

  • 地址。我们在网上购物的过程中填写地址时,经常会发现它分成了几个不同的部分让我们输入,比如省、市、区、街道、邮编等等。那么如果使用SharePoint默认功能的话,我们只能把这些分别存在一些栏中,这显然不好。自定义列表字段就可以把它们存在一个栏中,但是可以分别输入各个部分。(事实上,Todd的USAddress这个字段类型也是我见过的第一个自定义字段类型)
  • Email地址。如上所述,可以使用正则表达式加上一些合法性验证。
  • 评分。更加人性化的输入和输出,让用户使用时不在是只和枯燥的数字打交道。
  • 外部数据查阅。虽然默认有了BDC查阅和查阅项,但是有时我们可能会需要更灵活些的查阅,比如跨网站查阅列表内容(还记得么?这是2007支持的功能!但是并没有体现在默认界面上罢了)

当然,自定义字段类型并不是万能的,它有着这样那样的局限,而且其中很多都非常诡异:

  • 首先,自定义列表字段是不被office系列的客户端支持的。也就是说,我们觉得很好用的那个“文档信息面板”是不支持自定义字段类型的。我们在文档库中添加一个自定义列表字段时,甚至都会出现这样的提示:

image

如果你不记得什么是“文档信息面板”的话,喏(在线创建一篇文档时):

image

  • 其次,非常奇怪的,自定义字段类型中的值不能超过255个字符(即使你继承了多行文本也不行!),就“好像”它们都是从单行文本衍生出来似的(我们知道单行文本的最大长度就是255)。这是一个老外发现的,非常没道理的一个限制,那个老外最后用的方法是继承了多选这种字段类型,这样就可以多放几个255字符了,虽然选项数也是有限制的……
  • 另外,现在的自定义字段类型有一个很严重的bug,就是按照标准的编程方法(我指的是SDK里写的方法),它无法保存自定义的属性(每个字段类型都有些独特的属性,比如数值型中的最大值、最小值)。当然,这并不意味着我们就不能保存自定义属性,有一些解决方案去使用它(其中一种阳春白雪,从SharePoint存储自定义属性的原理入手,但是这个改起来超级麻烦;另外一种是我发明的,虽然看起来很丑陋,但事实证明有效且简单),我在后面会讲到具体怎么做。
  • 最后,我们开发人员最关注的就是,这个东西开发起来比较繁琐,尤其当你有很多需求要加进去时。虽然它并没有workflow那么深奥,但由于涉及到的东西比较多,所以还是有点难度的。还是Web部件和Event Handler容易啊……感叹一下。每次我讲自定义列表字段开发的时候,虽然我已经尽量把它涉及到的原理讲清楚了,但台下的反响还是云里雾里……不自己亲自做几个的话,恐怕是很难深入理解的。

一个自定义的字段类型如果算全了的话,可以分为5个部分(看,我说很繁琐吧……)

  1. 字段类。一个自定义的字段类型是继承自某个内置的字段类型的(这也是为什么我上次花了这么大功夫把内置的字段类型都罗列了一遍的原因),当然,我们也可以直接继承最基础的字段类型——SPField,但是这样要多做些事情(很遗憾,具体加什么我忘了-.-)。还是建议继承某种已有的吧(比如SPFieldText、SPFieldLookup、SPFieldMultiColumn之类的),大不了我们完全不用它默认的输入输出界面罢了。
  2. 字段值类。这是一个可选的部分。就像我上一次说的,如果字段的设计比较复杂的话,可能会需要字段值的类型,这种一般都用于一个字段中存储超过一个数据的情况(比如查阅项包含被查阅条目的ID和一个文本,Url包含地址和描述)。如果我们自己的字段类型需要有类似需求的话,可以继承一个已有的值类型,来写一个新的值类型。当然,如果原有的值类型能够满足我们的需求,直接用它就好了。
  3. 字段输入/显示控件。这也是一个可选的部分,但大多数情况下可能都要写,因为我们往往需要自定义输入的样式和输出的样式。这个控件可以使用一个User Control来做,因此支持可视化设计(如果愿意生写也可以……)
  4. 自定义属性的输入控件。同样是一个可选部分。自定义的属性对于一个自定义字段类型来说往往还是比较重要的,正是它体现了同一种字段类型下,一个字段和另一个字段的不同之处(比如查阅项查阅不同的列表)。本来这些自定义属性的输入是可以自动生成的,但由于刚刚说的那个bug,我们一般还是需要手动地去写一个自定义属性的输入控件,而且我们可以在这里也加入自定义的一些逻辑。这部分内容同样可以使用User Control,只不过需要再实现一个特殊的接口就行了。
  5. 字段定义文件。这是一个xml文件,每个自定义的字段类型都必须有(其实默认的那些字段类型也有),而且这个文件名必须以fldtypes_开头。这个文件中定义了关于该字段类型的一些基本信息(比如标题、类型、是否允许用户创建等等),还有它使用到的程序集信息、自定义属性的输入控件信息,另外还有各种显示样式(没错,这里也可以定义显示样式,而且支持一些诸如if、switch之类的条件判断,通过CAML格式实现),以及自定义属性(标准做法中的自定义属性在这里定义)。如果写这个文件时遇到了困难,我们可以参考一下默认的那些字段类型是怎么被定义的,此文件是那个很深的12目录中的"TEMPLATE\XML\FLDTYPES.XML"。

从另一个角度来说,自定义的字段类型也可以分成3个部分:程序集(dll)、控件(ascx)、描述文件(xml)。不妨先在此简要地介绍一下自定义字段类型的部署,很容易:把程序集扔进GAC里,把ascx放到"12\TEMPLATE\CONTROLTEMPLATES",把xml放到"12\TEMPLATE\XML",然后重启iis(一定要重启iis,仅回收应用程序池是不行的),然后就可以再创建栏那里看到新的字段类型了(如果我们没写错什么东西的话……)

从下一次开始,就是主要介绍以上那5个部分的写法,从中一一地展开介绍一下字段类型的工作机理。如果我能试出来字段类型之间通讯的话,我也会做一个介绍。

(未完待续)

posted @ | Feedback (3) | Filed Under [ SharePoint ]

Thursday, November 22, 2007

SharePoint中若干自定制开发的内容,从目前我接触到的来讲,从开发语言上首先可以分为两大类,.net类和C++类,其中C++类主要是关于搜索中的IFilter和Protocol Handler的编写,使用的是COM的技术,这个回头有时间再说吧(或者有条件的话可以找微软要几份文档,之前帮微软做过文档和几个demo)。

然后就.net类的来说,我认为最为复杂的有两个内容,一个是工作流(我指的是vs开发的工作流),开发SharePoint工作流的话,除了要对SharePoint工作流的一些概念有所了解、对InfoPath有所了解之外,最重要的是WF(Workflow Foundation),这个研究的不太多;另外一个比较复杂的东西,就是自定义列表字段类型。就几次培训的反馈来说,普遍认为这个很麻烦,如果之前没有看过相关资料的话,2、3个小时之内很难把这个东西学明白。

于是从今天开始,准备写一个自定义列表字段类型的专题,争取涉及到其中可能会用到的各个方面。

之所以先从“0”开始,因为这次内容先不涉及到自定义的字段类型,先来看一下SharePoint中内置的那些字段类型,以及他们在对象模型中是什么样的。

首先下面这张图相信如果用过SharePoint的人应该再熟悉不过了:

image

这张图上基本上涵盖了大部分SharePoint内置的字段类型。如果我们装的是moss的话,还会多一个“业务数据”类型。

其实在wss3.0中,还多了一个可能一般使用者很少会见到的内置字段类型,叫“评估范围”,这种字段类型只在“调查”列表中会出现,并且不能在其他种类的列表中使用(即使通过对象模型也不能把它加到一个普通列表或者文档库中)。在新建一个调查列表的时候,创建列表的页面中,不是“确定”按钮,而是“下一步”,点这个按钮就会提示我们输入一些问题,这个时候就可以看到这个“评估范围”字段类型了:

image

这个字段类型主要的作用就是打分(有点像是youtube里面给视频打分的那种机制),可以设置分成几个分值,并且可以选择是否有空的项目(默认是N/A),以及将这些分值划分为三档,每一档的名称(好像只能是三档):

image

它的输入界面和输出界面都比较友好:

image

image

以上就是这个不太常见的列表字段类型的大概介绍,觉得这个字段类型写的还是很好的,其实我们可以通过自定义字段类型的方式,写出更加强大的字段类型出来。在此之前,先来看一下在SharePoint的对象模型中,字段都是怎样描述的。

如果之前曾经接触过一写SharePoint开发,我们会知道在对象模型中描述字段的类是SPField(对应的集合类是SPFieldCollection),这个类描述了一个字段中常用的一些属性(比如标题、内部名称、默认值、是否允许为空等等,以及在wss3.0中新加的是否在新建/编辑/显示等界面上显示这个字段——这个功能是只能通过自己写代码完成的,对应的属性叫ShowIn****,这是一个nullable的bool值,和普通bool值的用法有所区别)。

那么实际上,在SharePoint中内置的那些字段类型也都有各自的对象模型与之对应,这些类一般叫做SPField****,它们都是SPField的子类,各自扩展了特有的一些属性设定(比如单行文本中的最大长度、数字中的小数点位数等),有些比较复杂的字段类型还会有值类型于之对应,这些类一般叫做SPField****Value(****和它对应的字段类型的类名中的部分相同)。下面先大致看一下常用的内置字段类型:

1、单行文本 - SPFieldText

这个可能是用的最为广泛的字段类型了,它的输入界面就是一个单行文本框,没有数据验证功能(除了是否为空)。可以设置最大长度(局限在255以内)。

2、多行文本 - SPFieldMultiLineText

输入界面是一个textarea,根据设置不同,可以是纯文本或者是带格式文本的(按照html格式保存的)。

3、数字 - SPFieldNumber

输入界面是textbox,但是带有数据验证(是否为数字,以及最大/最小值等)。

4、货币 - SPFieldCurrency

和数字其实差不多,只不过现实的时候会多一个货币符号。

5、是/否 - SPFieldBoolean

一个CheckBox

6、日期 - SPFieldDateTime

一个带picker的textbox,可以选择“日期和时间”或“仅日期”

7、选项(单选) -  SPFieldChoice

可以以dropdownlist或者radio button的形式出现。这个字段有点点特别,虽然它看上去只能存一个值,但其实它是多选类(SPFieldMultiChoice)的子类……

---------分割线(以上可以算是简单类型)--------------

8、选项(多选) - SPFieldMultiChoice

如果使用多选,那么是通过一组checkbox输入的。在这个类里面定义了这个字段中究竟有哪些选项(通过Choices属性,自然,作为它子类的SPFieldChoice也有这个属性)。于之相对应的,可以通过SPFieldMultiChoiceValue类来访问它的值。

9、评估范围 - SPFieldRatingScale

刚才介绍过了,它其实也是多选类(SPFieldMultiChoice)的子类。于之对应的值类型为SPFieldRatingScaleValue。

10、链接或图片 - SPFieldUrl

可以是链接,也可以是图片,它包含url和描述信息两个部分,通过其值类型SPFieldUrlValue可以很方便的得到这两部分。

11、查阅项 - SPFieldLookup

通过dropdownlist完成单选,一个特殊的listbox完成多选(wss3.0支持查阅项多选了!),由于每个被查阅的项会有id和文本,所以也需要有值类型,这个比较特殊,有两种值类型,SPFieldLookupValue和SPFieldLookupValueCollection(因为支持多选了嘛)。然后在SPFieldLookup类中,定义了要查阅哪个列表的哪个字段,以及是哪个网站上的列表。是的!wss3.0中的查阅项其实是支持跨网站查阅的(通过设定LookupWebId属性),但是在默认的界面上并没有暴露出一点。所以一个跨网站查阅项是一个很值得一做的自定义字段类型!

12、用户和用户组 - SPFieldUser

它的输入是通过一个带有AJAX支持的输入框完成的,这是一个很强大的控件。其实这个类是SPFieldLookup的子类,因为它们做的事情在本质上都差不多。相应的,其值类型SPFieldUserValue也是SPFieldLookupValue的子类,还有SPFieldUserValueCollection……

13、多栏 - SPFieldMultiColumn

这是另一个很特殊的字段类型,默认情况下我们无法直接使用它,使用它的唯一途径就是通过自定义字段类型继承它来完成我们的需求。顾名思义,这是一个能在一个字段中储存多个信息的字段类型。

-----------邪恶的分割线-----------------

好,那么现在我们已经了解了SharePoint内置的这些字段类型,之所以需要了解它们的目的除了方便“日常应用”外,最为重要的,我们正是通过继承这些字段类,来编写一个自定义字段类型的。也就是说,我们要先找到一个和需求功能类似的字段类型,继承它!

(未完待续)

posted @ | Feedback (9) | Filed Under [ SharePoint ]

Friday, November 16, 2007

近日同学所在某公司的SharePoint网站在打了补丁之后挂掉了(登陆不能,登陆页面也不出现,用的LDAP认证),然后他自己鼓捣出来之后,在我威逼(没有利诱)之下,把他关于SharePoint的部分笔记发给我了,贴到这里给大家看看,可能也会有人遇到类似的问题。

他们用的是WSS3.0 + LDAP认证方式,https加密传输,主要用于做文档管理,没有任何自己开发的代码在其中。

首先是关于崩溃问题(笔记记载如下):

前两天出了一点小故障,问题描述要比解决方案复杂得多。。
开始可以出现登录页面,但是登录上去就抱错,说找不到default页面,然后看到winows update里面有个sharepoint的升级,就运行了。重启了机器后sharepoint的务就挂了。。。
唯一能想到的修复方法就是运行那个sharepoint配置向导,但是第9步会说spadmin服务没有起,十分伤心。就扔下不管了。
今天有人要用了,只好硬着头皮看看,发现这次配置向导竟然通过了。唉,微软的东西就是搞不懂,不过网站还是起不来,就乱改了一通iis配置,然后又用配置向导修复了好几次,终于可以出现登录页面了,但总说我登录不上。研究了半天估计是ldap配置出了问题,果然一检查是把上面2的web.config给覆盖了,于是恢复了就好了。。。
现在想一想当初可能就是升级后把一些配置给我覆盖了吧。。

然后是关于WSS3.0如何使用LDAP认证的问题:

基本按照网上的一些步骤配置,不过有些改动,详细内容可以参考这个网页:
http://www.sharepointblogs.com/helloitsliam/archive/2006/08/15/10027.aspx
这里只说一下具体做法
1. 从一个装了moss2007的机器上copy一个microsoft.office.server.dll文件放在桌面上,在C:\Program Files\Common Files\Microsoft Shared\web server extensions\12\ISAPI目录,然后将这个文件拖进c:\WINDOWS\assembly目录,注意一定要拖进。。
2. 修改sharepoint管理中心网站和web网站的web.config文件,默认在c:\Inetpub\wwwroot\wss\VirtualDirectories\80(和另一个管理端口)
在<machineKey>这行和</system.web>之间加入:
    <membership defaultProvider="LdapDemoMembership">
      <providers>
        <add name="LdapDemoMembership" type="Microsoft.Office.Server.Security.LDAPMembershipProvider, Microsoft.Office.Server, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71E9BCE111E9429C" server="xxx.xxx.xxx" port="389" useSSL="false" useDNAttribute="false" userNameAttribute="uid" userContainer="ou=xxx,dc=xxx,dc=xxx,dc=xxx" userFilter="(ObjectClass=*)" scope="Subtree" otherRequiredUserAttri
butes="uid,cn" />

      </providers>
    </membership>
保存关闭。注意useDNAttribute="false"一句比较重要,搜索的资料很多没有说,否则会连不上。
3. 打开sharepoint的管理中心(可以从开始->管理工具->),应用程序管理,验证提供程序,编辑现有的默认验证,验证类型选中表单,这里要打开一下匿名的权限(注意稍后再给禁掉),成员身份提供程序要和前面添加的一致,如LdapDemoMembership,角色管理不用填,最下面启用客户端集成,然后保存。
4. 手动添加一个管理员帐号(过后可以再删掉),还是应用程序管理,Web应用程序的策略,添加用户,区域选择默认(或自己设的网站区域),这是用户里应该能够识别ldap服务器上的所有用户,给一个完全控制权限。
5. 访问sharepoint的web网站,会出现登录框,用刚添加权限的帐号登录,点右上网站操作,网站设置,高级权限设置里面的匿名权限打开。然后回去关闭掉4中打开的匿名访问。这样可以做到需要ldap认证,但默认用户有一个访问者的权限,通过更改sharepoint网站中的访问者权限就可以限制普通用户的权限(已经很低了)。

关于https的设置:

控制面板,添加删除windows组件里先添加证书服务,随便起个名字。
管理您的服务器,管理此应用程序服务器,对sharepointweb端和后台管理网站都要做:属性,目录安全性,服务器证书,一路下去,生成一个txt文件。
更改默认网站的端口,比如8080,启动。
浏览器中访问http://localhost:8080/certsrv,申请一个证书,高级申请证书,使用base64...,将txt文件中begin和end之间的部分copy过去,提交。
管理工具,证书颁发机构,挂起的申请,改刚才的id颁发证书。
再登录刚才localhost网址选查看挂起的证书申请的状态,可以下载DER编码的证书保存。
回到开始的服务器网站属性,再选择服务器证书,处理挂起的请求并安装证书。
完毕后就可以https访问了。最后在目录安全性,编辑里勾上要求安全通道和128位加密。

都是原文照搬过来的,我是不是太懒了。。。。

准备弄完手头的连载之后开始写一个自定义列表字段的专题,或者各位看客有啥想了解的关于开发方面的(除了工作流-.-)东东也可以提一下,嗯嗯

posted @ | Feedback (1) | Filed Under [ SharePoint ]

Thursday, September 27, 2007

在水木上看到的,Excel 2007在公式计算中有一个超级弱智的大bug:

计算乘法时,当计算结果等于65535,且两个乘数中有一个是小数时,有些时候结果会变成100000……

image

真是不知道产品组是怎么搞的。。。这种毫无理由的bug。。。

想当年似乎有一种计算器还是计算芯片,当计算两个特定的数相乘的时候,结果是错的

posted @ | Feedback (20) | Filed Under [ 其他 ]

Sunday, September 16, 2007

可以像写SQL语句那样来写CAML查询,点击这里免费下载。

我没有经过太大量的测试(没有覆盖到每种可能的分支),目前还处在beta版,欢迎大家试用。

如果有什么问题,可以在这里回复,或致信通向分享:feedback(at)CollaDec.com。感谢支持!

 

其实之前也有一些国外的人做了一些生成CAML查询的东西(毕竟CAML还是太难写了,主要问题倒不在于xml,而在于那些内部名称)

不过看了一眼之前的那个CAML Generator,本质上还是像xmlwriter那样去加那些结点,而且没有解决内部名称的问题

然后想写一个客户端去生成CAML,就像SQL Server里做视图的那样,后来觉得还是不太方便,索性打算写一个直接像SQL那样的语句去直接查询内容

其实这个东西的核心内容就是一个T-SQL语句的解析器

之前一直想不好怎么做比较方便,也参考了一些开源的解析器,帮助不是很大,这也是拖了很久的原因。

最近在做实验室的程序的时候做了类似的东西,于是借着手熟就顺手写了

主要就是借助几个数组去存那些查询字段、查询条件、排序字段、分组字段,

手写了一个状态机(懒得再去找开源状态机组件了,而且还得再带个dll,比较麻烦),标记出每个成分后面允许的内容(比如在select后面的返回字段后面,可以是一个逗号,也可以是where、order或者group),难度并不大,只要想清楚了就是个体力活。不过估计这个状态机应该还能再精简一些,等有空再分析分析吧。

另外一个比较核心的部分就是查询表达式的处理,把那种查询条件转换成xml格式的,这个其实就相当于表达式计算问题,随便找本数据结构的书上应该就有(分成两步:中缀表达式转后缀表达式、后缀表达式的计算)。

然后就是把那些列表名称、字段名称该分析的分析、该转换的转换,这个就很容易了。

下一步对这个的打算,除了找找bug、优化一下算法,可能考虑添加对跨列表、跨网站查询的支持,以及对moss中search的支持(这个可能比较麻烦)。

给个小sample:

SPWeb web = SPContext.Current.Web;
string queryStr = "SELECT * FROM 通知 WHERE ID>10";
FriendlyQuery query = new FriendlyQuery(web, queryStr);
query.RowLimit = 100;
query.Scope = FriendlyQuery.QueryScope. AllItemsAndFolders;
SPListItemCollection items = query.GetItems();
foreach(SPListItem i in items)
    Response.Write(i.Title + "<br/>");

posted @ |