7

我有一个网站内容类型,用于整个网站集中的少数列表。在该内容类型中,我描述了一个事件接收器来处理 ItemAdding 事件。这工作正常。现在我需要更新内容类型,以便同时处理 ItemUpdating。在我的脑海中,我尝试简单地修改我的内容类型的 xml,因为这似乎允许简单的版本跟踪。从某种意义上说,这很有效,因为我的更新应用于站点内容类型,但没有应用于我一直使用此内容类型的列表。这是预料之中的。然后我注意到 SharePoint SDK 对此持冷淡的看法

在安装并激活该内容类型之后,在任何情况下都不应更新该内容类型的内容类型定义文件。Windows SharePoint Services 不跟踪对内容类型定义文件所做的更改。因此,您无法将对站点内容类型所做的更改下推到子内容类型。

SDK 然后指向几个部分,这些部分描述了如何使用 UI 或代码来推送更改。由于 UI 没有提供事件接收器的挂钩,我想我将选择代码路径。

我想我可以做这样的事情,只需将一个新的事件接收器添加到列表的内容类型副本中:

SPList list = web.Lists["My list"];
SPContentType ctype = list.ContentTypes["My content type"];
// Doesn't work -- EventReceivers is null below.
ctype.EventReceivers.Add(SPEventReceiverType.ItemUpdating, 
                         "My assembly name", "My class name");

但问题是 ctype.EventReceivers 在这里为空,即使我已经将 ItemAdding 连接到这个列表。它似乎已移至列表本身。因此,该列表具有有效的 EventReceivers 集合。

SPList list = web.Lists["My list"];
list.EventReceivers.Add(SPEventReceiverType.ItemUpdating, 
                        "My assembly name", "My class name");

所以,我有几个问题:

  1. 只是将任何新的事件接收器直接添加到列表中而完全忘记我的内容类型是正确的方法吗?
  2. 为了完成这种变化,在配置管理方面处理这个问题的最佳方法是什么?我应该创建一个简单的控制台应用程序来查找所有适当的列表并修改每个列表吗?还是以某种方式创建功能是更好的选择?无论哪种方式,似乎这种变化都会自行消失,并且可能需要使用这种内容类型的未来开发人员很难发现。
4

3 回答 3

2

添加 EventReceiver 后是否调用了 ctype.Update(true)?如果你不这样做,它就不会被持久化。并且不要使用 List 内容类型,而是使用 SPWeb.ContentTypes。

这段代码对我有用:

var docCt = web.ContentTypes[new SPContentTypeId("0x0101003A3AF5E5C6B4479191B58E78A333B28D")];
//while(docCt.EventReceivers.Count > 0)
//  docCt.EventReceivers[docCt.EventReceivers.Count - 1].Delete();
docCt.EventReceivers.Add(SPEventReceiverType.ItemUpdated, "ASSEMBLYNAME, Version=1.0.0.0, Culture=neutral, PublicKeyToken=c5b857a999fb347e", "CLASSNAME");

docCt.Update(true);

true 参数意味着它也被下推到所有子 ContentTypes。(即使用内容类型的所有列表)。

于 2009-07-02T21:20:35.093 回答
1

要回答您问题的第二部分,这是一件棘手的事情,因为 sitecollection 上内容类型的更改不会被推送到使用它的列表中。“副本”本质上是由站点集合中的字段组成的,在您将内容类型添加到列表后,它们之间不再存在链接。我认为这是因为您应该在不影响站点集合的情况下对列表进行更改。无论如何,我对这个“问题”的贡献,以及我是如何解决它的,包括使 xml 成为“主”,在 featurereceiver 中我拉出 xml 并找到所有使用 contenttype 的地方并从那里更新 contenttypes(真的列表级别上的 fieldrefs) 以匹配 xml 中的那个。代码类似于:

var elementdefinitions = properties.Feature.Definition.GetElementDefinitions();

foreach (SPElementDefinition elementDefinition in elementdefinitions)
{
   if (elementDefinition.ElementType == "ContentType")
   {
     XmlNode ElementXML = elementDefinition.XmlDefinition;

     // get all fieldrefs nodes in xml
     XmlNodeList FieldRefs = ElementXML.ChildNodes[0].ChildNodes;

     // get reference to contenttype
     string ContentTypeID = ElementXML.Attributes["ID"].Value.ToString();
     SPContentType ContentType = 
         site.ContentTypes[new SPContentTypeId(ContentTypeID)];

     // Get all all places where the content type beeing used
     IList<SPContentTypeUsage> ContentTypeUsages = 
        SPContentTypeUsage.GetUsages(ContentType);
   }
}

接下来是将 xml xml 中的 fieldrefs 与列表中的字段(由 ID 属性完成)进行比较,并确保它们相等。不幸的是,我们无法更新 SPFieldLink 类(fieldref)上的所有内容,并且(是的,我知道它不支持)在这里我实际上使用反射来更新这些值(fe ShowInEditForm)。

于 2009-07-03T07:26:37.240 回答
0

至于你问题的第二部分,我想介绍一下我们过去为类似情况所做的工作。在我们的情况下,我们需要几个不同的脚本:一个允许我们将内容类型更新传播到所有 Web 中的所有列表,另一个将母版页/页面布局重置为站点定义(未自定义的表单)。

因此,我们为每个操作创建了一些自定义 stsadm 命令。这样做很好,因为脚本可以放入源代码管理中,并且它实现了已经存在的 stsadm 接口。

自定义 SharePoint stsadm 命令

于 2009-07-02T21:47:14.900 回答