2008年7月6日,星期日

SPDataSource-每个SharePoint开发人员's friend (part 1)

几乎每个SharePoint开发人员迟早都需要编写代码以从列表中检索所有项目并显示它们-在页面上,或者通常在诸如下拉列表控件之类的控件中。一个示例可能是检索国家列表,或者可能是某种形式的人称:

DropdownFromList

显然,将这​​些值存储在列表中有很多好处,因为我们(或客户)可以轻松地添加/编辑/删除项目。为了实现这一点,开发人员的第一个想法可能是编写如下代码:

private void bindPersonTitles()
{
// the name of the DropDownList control we are populating is ddlPersonTitles..
using (SPWeb configWeb = SPContext.Current.Site.AllWebs["configuration"])
{
SPList titlesList = configWeb.Lists["PersonTitles"];

foreach (SPListItem titleItem in titlesList.Items)
{
ddlPersonTitles.Items.Add(new ListItem(titleItem.Title, titleItem.ID.ToString()));
}
}
}


没关系除非我们要过滤或排序列表项,否则我们确实应该使用CAML查询而不是遍历所有项-下面的代码显示了这一点(在名为“ SortOrder”的列上进行排序),并且在前面的示例中,我使用数据绑定,而不是“手动”遍历项目:


private void bindPersonTitlesByCamlQuery()
{
using (SPWeb configWeb = SPContext.Current.Site.AllWebs["configuration"])
{
SPList titlesList = configWeb.Lists["PersonTitles"];
SPQuery query = new SPQuery();
query.Query = "<OrderBy><FieldRef Name=\"SortOrder\" /></OrderBy>";
SPListItemCollection titlesItems = titlesList.GetItems(query);

// showing alternative of using data-binding rather iterating through items..
ddlPersonTitles.DataSource = titlesItems;
ddlPersonTitles.DataTextField = "Title";
ddlPersonTitles.DataValueField = "ID";
ddlPersonTitles.DataBind();
}
}

再好除了我不禁要思考 "所有这些只是为了从列表中取出项目并将其放入下拉列表中?" 当然,必须有更好的方法。 Microsoft每次需要执行此操作时,肯定不会在SharePoint中的每个位置重复上述代码吗?答案是否定的,他们使用了以下方法:

SPDataSource

简而言之,SPDataSource是一个Web控件,可实现IDataSource并省去了编写上述代码的麻烦。很棒的事情是它非常灵活,而且正如我们将看到的,它的用途超出了您的想象。不过,最好的是,作为控件它可以以声明方式使用,因此我可以将下拉列表绑定到列表,而无需编写C#或VB.Net代码的任何一行-我要做的就是正确设置属性。我们将在稍后详细介绍细节,但是替换最后一个代码示例的标记如下所示:


<SPWebControls:SPDataSource runat="server" ID="dsPersonTitles" DataSourceMode="List" 
SelectCommand="<Query><按订单><FieldRef Name='SortOrder' Ascending='true' /></按订单></Query>"
<SelectParameters>
<asp:Parameter Name="WebUrl" DefaultValue="/configuration/" />
<asp:Parameter Name="ListName" DefaultValue="PersonTitles" />
</SelectParameters>
</SPWebControls:SPDataSource>

<asp:DropDownList runat="server" ID="ddlPersonTitles" CssClass="title" DataSourceID="dsPersonTitles" DataTextField="Title" DataValueField="ID">
</asp:DropDownList>

因此,我们正在执行以下操作:
  • 将SPDataSource的'DataSourceMode'设置为'List'-我们将很快检查其他可能的值

  • 将“ SelectCommand”设置为我们要使用的CAML查询-在这里,我们只是再次对“ SortOrder”字段进行排序

  • 通过提供名为'WebUrl'和'ListName'的ASP.Net 2.0参数对象,告诉SPDataSource我们要使用哪个列表-我们稍后将深入探讨

  • 最后,我们通过将DataSourceID指定给我们提供给SPDataSource的ID来将下拉列表绑定到数据,并说出结果集中要用于下拉列表的“文本”和“值”的字段。顺便说一句,我建议使用ID作为值的名称和Title作为文本的名称(如上所示),以便轻松创建SPLookupValue来更新列表项-第2部分中的更多内容

我们才刚刚开始看到SPDataSource的强大功能,但是由于以下几个原因,我喜欢这种方法:
  • 我的查询的详细信息未在编译后的代码中指定,因此,如果列表中的任何内容发生了变化(例如,我们重组了网站),我都不必重新编译和重新部署程序集

  • 更少的自定义代码,更少的错误!

  • 设置属性可以说比编写代码更简单

因此,让我们更深入地了解我们可以做些什么-我们将在本文中介绍SPDataSource的“模式”以及如何在第2部分中动态传递参数来控制查询。

SPDataSource的不同“模式”

SPDataSource不仅限于从列表中获取项目(DataSourceMode ='List')。其他可能性是:

  • CrossList-与在网站集中的所有列表中使用SPSiteDataQuery进行查询类似(有关此示例,请参阅本文结尾处链接的SharePoint Designer团队博客文章)

  • ListItem-显示单个列表项中的字段值

  • 网站-列出网站集中的所有网站

  • ListOfLists-列出网络中的所有列表

对于最后两种模式,我可以绑定,但是在计算要用于控件的'DataTextField'/'DataValueField'的值时遇到了一些困难。我试图简单地获取Web或列表名称,但结果集中没有任何明显的值,如“ Title”,“ ListName”等。我找不到与此有关的任何其他信息,但是我敢肯定,通过更多的反复试验可以解决该问题。 “ ListItem”模式可能很有趣-在以下示例中,我将单个列表项绑定到DataGrid,以显示该项中的选定字段,该字段本身是通过使用“ ListItemID”属性来选择的:



<SPWebControls:SPDataSource runat="server" ID="dsPeople" DataSourceMode="ListItem" UseInternalName="true"> 
<SelectParameters>
<asp:Parameter Name="WebUrl" DefaultValue="/configuration/" />
<asp:Parameter Name="ListID" DefaultValue="34F91B0C-FCF2-455A-ABBA-67724FB4024A" />
<asp:Parameter Name="ListItemID" DefaultValue="1" />
</SelectParameters>
</SPWebControls:SPDataSource>

<asp:GridView ID="grdPeople" runat="server" DataSourceID="dsPeople"
AutoGenerateColumns="False">
<Columns>
<asp:BoundField DataField="FullName" HeaderText="Blogger name" />
<asp:BoundField DataField="WorkCity" HeaderText="City" />
<asp:BoundField DataField="Blog_x0020_URL" HeaderText="Blog URL" />
</Columns>
</asp:GridView>

基于具有以下字段的基础列表项,这将给出类似的内容(尚未应用格式):

SPDataSource_ListItem_DataGrid

我发现我必须指定UseInternalName ="true"并在此模式下使用ListID而不是ListName参数。

下次-将参数传递给SPDataSource

到目前为止,我们已经研究了通过使用标准ASP.Net参数控件并在DefaultValue'属性中指定值来提供参数。实际上,ASP.Net具有范围广泛的参数控件,它们可以完成从某个地方检索参数并将其传递给SPDataSource的工作,因此我们将在下一次介绍。此外,由于我们经常使用SPDataSource将数据绑定到表单控件,因此我们将研究获取所选项目的常见情况 表单控件以保存回SharePoint中的查找字段。

<updated>我提到但未链接到SPD博客文章的链接是 http://blogs.msdn.com/sharepointdesigner/archive/2007/04/24/spdatasource-and-rollups-with-the-data-view.aspx -这里的重点主要是将SPDataSource与DataView一起使用,但是有一些不错的信息和示例。</updated>

14条评论:

匿名 said...

我认为您在谈论此链接?

http://blogs.msdn.com/sharepointdesigner/archive/2007/04/24/spdatasource-and-rollups-with-the-data-view.aspx

匿名 said...

伟大的文章克里斯。我一直认为,仅花费大量代码即可从SharePoint列表中检索项目列表。遗憾的是,到目前为止我尚未阅读的某些SharePoint应用程序开发书中都没有引入SPDataSource。

克里斯·奥'Brien说过...

Renaud - oops, yes thanks for that. Article now 更新 :-)

匿名 said...

克里斯,你好
我到处搜索,但找不到答案。这是我对这个问题的最后一次尝试。
我希望在SPDatasource中使用updatecommand / insertcommand,但没有看到任何示例。
谢谢您的帮助。谢谢。

克里斯·奥'Brien说过...

@VV,

我担心99%的SPDataSource不支持插入/更新操作。如果您需要插入/更新,则需要使用SPList.Items.Add()等对这些操作进行编码。

如果您听到其他不同的话,我很想知道。

HTH,

克里斯。

匿名 said...

感谢克里斯的回复!

也许您是对的,但是为什么SPDatasource具有名为insertcommand / updatecommand的属性?这些都是误导。我花了很多时间来使这项工作生效,因为我必须在项目中使用大量可批量编辑的网格视图。现在,我必须看看其他选项。
我已经阅读了您的两篇文章,它们对您很有帮助。保持良好的工作!

克里斯·奥'Brien说过...

@VV,

我只是想回应一下,其原因是InsertCommand和UpdateCommand属性是从System.Web.UI.DataSourceControl继承的(但没有实现),但经检查并非如此!

因此,现在看来SPDataSource会定义这些属性而不实现它们是很奇怪的。像你一样,我没看过 任何 使用样本。因此,我仍然相信SPDataSource不会使用它们-尤其是当您认为CAML(由SelectCommand属性使用)没有执行插入/更新操作的语法时,尤其如此。

正如我所说,如果您听到不同的话,我将非常感兴趣!

干杯,

克里斯。

匿名 said...

我不确定这是否可以完全解决难题,但是SPDataSource实现了IDataSource,其GetView方法返回的DataSourceView定义了ExeuteDelete,ExecuteInsert,ExecuteSelect和ExecuteUpdate方法。

因此,通过ipmlementing IDataSource,SPDataSource必须至少具有一些有关更新/插入/删除操作的知识,即使这些操作只是被存根。

未知说过...

我尝试了您的代码,并收到警告说"OrderBy" isn't spdatasource的公共属性。那是正常的吗?

克里斯·奥'Brien说过...

@Albert,

猜测,这会告诉我您的标记是't格式正确(我'm assuming you'重新使用SPDataSource示例而不是CAML查询)。你能贴上你的东西吗're using?

谢谢,

克里斯。

silas2 said...

您将建议什么准则来决定是否使用熟悉的(并且可能包装得很好)Asp.Net数据绑定控件,以及执行xml / xsl / caml / html混合的新内容?看起来很冗长。

克里斯·奥'Brien说过...

@ silas2,

那'这是一个好问题。 XML + XSLT的性能可能很高,很多年前,我在Content Management Server中使用了这种方法:)

通常,这取决于您从API获得的信息'重新使用-如果它为您提供XML,请不要't将其序列化为对象,只需对其进行转换即可。如果它给您物体,请不要'反序列化它们,对它们进行数据绑定!

不然你'能够通过正确的互联网搜索找到良好的性能比较-有几个变量,所以我赢了'在这里不要评论太多。

HTH,

克里斯。

未知说过...

克里斯你好,
谢谢你的文章。我们碰到它是因为我们认为我们以某种方式弄乱了绑定。
这是标记(Sharepoint 2010):

__designer:bind ="{ddwrt:DataBind('u',concat('ff6',$Pos),'SelectedValue','SelectedIndexChanged','ID',ddwrt:EscapeDelims(string(@ID)),'@Country')}"

但是,在该页面上,下拉列表未显示项目名称("Germany"),但有一个链接(在下拉列表中!),如下所示:

<a href="http://服务器名称/my/personal/Lab04/_layouts/listform.aspx?PageType=4&ListId = {FA572B1D-F8A4-4A7B-BC3D-E1EAE92F20DE}&ID=4&RootFolder=*">Germany</a>

你有什么想法吗?
谢谢,

克里斯·奥'Brien说过...

@sharepoint,

对不起'我不太确定你在做什么'我在那里做过。希望你能排序。

克里斯。