次の方法で共有


SharePoint Foundation 2010 のイベント レシーバーを使用する (2/2)

概要:  Microsoft SharePoint Foundation 2010 のイベント レシーバーを使用すると、SharePoint オブジェクトで特定のアクションが発生したときに、ユーザー設定コードで応答できます。この記事では、イベントを使用して SharePoint アプリケーションを拡張する方法について、実際的な例で説明します。

最終更新日: 2015年3月9日

適用対象: Business Connectivity Services | Open XML | SharePoint Designer 2010 | SharePoint Foundation 2010 | SharePoint Online | SharePoint Server 2010 | Visual Studio

この記事の内容
実際的なイベント使用例
例 1: お知らせのブロードキャスト
例 2: アイテムの分割
例 3: ドキュメントのソースの追跡
例 4: 取り消しとリダイレクト
例 5: イベントのログ記録
まとめ
その他の技術情報

提供元:  Ali Badereddin、Microsoft Corporation | Nick Gattuccio、Microsoft Corporation

目次

  • 実際的なイベント使用例

  • 例 1: お知らせのブロードキャスト

  • 例 2: アイテムの分割

  • 例 3: ドキュメントのソースの追跡

  • 例 4: 取り消しとリダイレクト

  • 例 5: イベントのログ記録

  • まとめ

  • その他の技術情報

この記事は、「SharePoint Foundation 2010 のイベント レシーバーを使用する (1/2)」の続きです。

実際的なイベント使用例

Microsoft SharePoint Foundation 2010 のイベント モデルについて理解した後は、実際にイベント処理コードを記述してみます。この記事の以降の項では、SharePoint イベント モデルをさまざまな方法で使用する 5 つの例について説明します。

  • お知らせのブロードキャスト   サイト コレクション内の多数のサイトに追加されるお知らせをすべて、ルート サイトのお知らせ Web パーツに表示します。

  • アイテムの分割   リストにアイテムを追加したときに、そのアイテムが自動的に 2 つ以上のアイテムに分割されるようにします。この例では、Before イベント レシーバーでエラーを発生させずにイベントを取り消す方法とプロパティ バッグを使用する方法も示します。

  • ドキュメントのソースの追跡   ドキュメント ライブラリ内のドキュメントを編集したときに、メタデータ プロパティが更新されるようにします。この例では、プロパティの昇格と降格の方法を示します。

  • 取り消しとリダイレクト   ユーザー操作を取り消し、エラー ページにリダイレクトします。

  • イベントのログ記録   サイト コレクション内で発生する各イベントを、サイトに格納されるリストのリスト アイテムとして記録します。

これらのサンプルごとに、Microsoft Visual Studio ソリューションをダウンロードできます。

サンプル参照時の参考用に、SharePoint イベント モデルの概略を次に示します。表 3 は、スコープ別に SharePoint Foundation 2010 のすべてのイベント レシーバー、それらの対象クラス、関連付けられるイベント ホストを示します。

表 3. スコープ別イベント レシーバー

スコープ

メソッド

クラス

ホスト

サイト コレクション

  • SiteDeleting

  • SiteDeleted

SPWebEventReceiver

  • サイト コレクション

Web

  • WebAdding

  • WebProvisioned

  • WebDeleting

  • WebDeleted

  • WebMoving

  • WebMoved

SPWebEventReceiver

  • サイト コレクション Web

リスト

  • ListAdding

  • ListAdded

  • ListDeleting

  • ListDeleted

SPListEventReceiver

  • サイト コレクション Web

  • リスト テンプレート

リスト

  • EmailReceived

SPEmailEventReceiver

  • サイト コレクション

  • Web

  • リスト テンプレート

  • リスト インスタンス

フィールド

  • FieldAdding

  • FieldAdded

  • FieldUpdating

  • FieldUpdated

  • FieldDeleting

  • FieldDeleted

SPListEventReceiver

  • サイト コレクション

  • Web

  • リスト テンプレート

  • リスト インスタンス

アイテム

  • ItemAdding

  • ItemAdded

  • ItemUpdating

  • ItemUpdated

  • ItemDeleting

  • ItemDeleted

  • ItemCheckingIn

  • ItemCheckedIn

  • ItemCheckingOut

  • ItemCheckedOut

  • ItemFileMoving

  • ItemFileMoved

  • ItemFileConverted

  • ItemAttachmentAdding

  • ItemAttachmentAdded

  • ItemAttachmentDeleting

  • ItemAttachmentDeleted

SPItemEventReceiver

  • サイト コレクション

  • Web

  • リスト テンプレート

  • リスト インスタンス

  • コンテンツ タイプ

ワークフロー

  • WorkflowStarting

  • WorkflowStarted

  • WorkflowCompleted

  • WorkflowPostponed

SPWorkflowEventReceiver

  • サイト コレクション

  • Web

  • リスト テンプレート

  • リスト インスタンス

  • コンテンツ タイプ

例 1: お知らせのブロードキャスト

この例では、サイト コレクションに多数のサイトがあり、ルート サイトでお知らせ Web パーツを使用するものとします。このシナリオの目的は、サイト コレクションのルート サイトに配置したお知らせ Web パーツに、各サイトに投稿されたすべてのお知らせを表示することです。

クリックしてコードを取得コード サンプルのダウンロード: SharePoint 2010: Using Event Receivers, Example 1: Broadcast Announcements (英語)

デザイン

サイト コレクションのルート サイトにお知らせリストがあることを前提とするので、まず、ルート サイトのホーム ページにこのリスト用の Web パーツを追加します。

お知らせ Web パーツを追加するには

  1. サイト コレクションのルート サイトのホーム ページへ移動します。

  2. [ページ] タブをクリックし、[ページの編集] をクリックします。

  3. [挿入] タブをクリックし、[既存のリスト] をクリックします。ルート サイトのすべてのリストとドキュメント ライブラリが表示されます。

  4. [お知らせ] リストをクリックし、[追加] をクリックします。

次に、サブサイトに投稿されたすべてのお知らせをルート サイトのお知らせリストにコピーする必要があります。これを行うには、ItemAdded イベント レシーバーを作成し、このレシーバーで、(お知らせリスト テンプレートに基づく) リストに追加されたすべてのアイテムをルート サイトのお知らせリストにコピーします。このイベント ロジックは、サイト コレクション内の各サイトのすべてのお知らせリスト (ルート サイトのお知らせリストを除く) でトリガーされる必要があります。

実装

Microsoft Visual Studio 2010 で、SharePoint 2010 イベント レシーバー プロジェクト テンプレートに基づいてプロジェクトを作成します。ソリューションをサンドボックスとして展開することを選択します。SharePoint カスタマイズ ウィザードで、図 6 のように、イベント ソースとしてお知らせリストを選択し、オーバーライドするイベントとして ItemAdded を選択します。

図 6. SharePoint カスタマイズ ウィザード

SharePoint カスタマイズ ウィザード

この操作によって、Web スコープに新しいフィーチャーが作成され、次に示すように、お知らせリスト テンプレート (ListTemplateId="104") に ItemAdded イベント レシーバーをバインドする <Receivers> 要素が含まれます。

<Receivers ListTemplateId="104">
  <Receiver>
    <Name>EventReceiver1ItemAdded</Name>
    <Type>ItemAdded</Type>
    <Assembly>$SharePoint.Project.AssemblyFullName$</Assembly>
    <Class>BroadcastAnn.EventReceiver1.EventReceiver1</Class>
    <SequenceNumber>10000</SequenceNumber>
  </Receiver>
</Receivers>

表 4 で、<Receiver> 要素内の各種要素について説明します。

表 4. Receiver 要素の要素

要素

説明

この例における値

Name

イベント レシーバー バインドの名前。

EventReceiver1ItemAdded。任意の名前を指定できます。

Type

イベントの種類。SPEventType 列挙体のいずれかの値のテキスト表現を使用できます。

ItemAdded。

Assembly

イベント レシーバー コードが含まれる DLL の完全なアセンブリ名。

$SharePoint.Project.AssemblyFullName$。この名前は、Visual Studio 2010 でソリューションをビルドするときに、完全なアセンブリ名に変換されます。

Class

SPEventReceiverBase から継承され、イベント レシーバー コードが含まれる (<名前空間>.<クラス> という書式の) 名前空間とクラス。

BroadcastAnn.EventReceiver1.EventReceiver1。"BroadcastAnn.EventReceiver1" が名前空間で、"EventReceiver1" がクラス名です。

SequenceNumber

イベントを実行する順序。たとえば、同じイベント ホストに 2 つの ItemAdding イベントがバインドされている場合、シーケンス番号が小さいイベントから順に実行されます。

10000。基本的に、これが既定値です。

Synchronization

イベントが同期か非同期かを指定します。After イベントは非同期です。

同期か非同期かを指定しないので、After イベントである ItemAdded の既定のモードである非同期になります。

サイト コレクション内のすべてのサイトでこのイベントがトリガーされるようにするには、フィーチャーのスコープをサイトに変更する必要があります。このようにすると、サイト コレクションでフィーチャーをアクティブ化するときにこの機能が有効化されるので、すべてのサブサイトでフィーチャーをアクティブ化する必要がありません。フィーチャーのサイト スコープはサイト コレクションを意味し (図 7)、Web スコープはサイトを意味します。

図 7. フィーチャーのスコープの設定

機能の範囲の設定

次に、EventReceiver1.cs というファイルを開き、ItemAdded イベントにコードを追加します。このコードでは、サブウェブのお知らせリストに追加されたアイテムを、ルート Web のお知らせリストにコピーします。また、お知らせの作成者の名前をタイトルの末尾に追加し、お知らせが作成されたサブ Web の URL を本文の末尾に追加します。

public override void ItemAdded(SPItemEventProperties properties)
{
    // Get a reference to the site collection.
    SPSite site = properties.OpenSite();

    // Get a reference to the current site.
    SPWeb currentWeb = properties.OpenWeb();

    // Get a reference to the root site.
    SPWeb rootWeb = site.RootWeb;

    // Skip if the root web is the same as the current web.
    if (rootWeb.Url == currentWeb.Url)
    {
        return;
    }

    // Get the current list.
    SPList currentList = properties.List;

    // Get the announcement list on the root site.
    SPList rootList = rootWeb.Lists["Announcements"];

    // Get the list item that was added.
    SPListItem currentListItem = properties.ListItem;

    // Add the announcement item to the list on the root web.
    SPListItem rootListItem = rootList.Items.Add();
    foreach (SPField field in currentList.Fields)
    {
        if (!field.ReadOnlyField)
        {
            rootListItem[field.Id] = currentListItem[field.Id];
        }
    }

    // Append the user display name to the title.
    rootListItem["Title"] += " - " + properties.UserDisplayName;

    // Append the web URL to the body.
    rootListItem["Body"] += string.Format("This announcements was made by {0} on subweb {1}",
      properties.UserLoginName, properties.WebUrl);

    rootListItem.Update();
}

ここまで準備できたら、ソリューションをビルドし、デバッガーを開始できます。この操作によって、ソリューションが作成され、SharePoint サイト コレクションに展開され、サイト コレクションのホーム ページでブラウザーが起動されます。サイト コレクションにお知らせリストがあることを確認してください。

最後に、チーム サイト テンプレートに基づいて新しいサブサイトを作成します。お知らせリストにアイテムを追加し、そのアイテムのコピーが、図 8 のように、ルート サイトのお知らせリストに表示されることを確認します。

図 8. ルート サイトのお知らせリストに追加されるアイテム

ルート サイトの Announcements リストに追加するアイテム

例 2: アイテムの分割

この例の目的は、リストに 1 つのアイテムが追加されたときに、そのアイテムを 2 つの新しいアイテムに分割することです。たとえば、あるユーザーが "Xbox 360 Bundle" というアイテムを追加したときに、そのアイテムをリストに追加する代わりに "Xbox 360" と "Kinect" という別の 2 つのアイテムがリストに追加されるようにする場合などです。また、別の例として, .zip ファイルをアップロードしたときに、そのファイルから展開されるそれぞれのファイルを別個のアイテムとして追加する場合なども考えられます。

アイテムを分割するシナリオに対応するために、この例では、Before イベント レシーバーでエラーを発生させずにアクションを取り消す方法についても説明します。

クリックしてコードを取得コード サンプルのダウンロード: SharePoint 2010: Using Event Receivers, Example 2: Splitting Items (英語)

デザイン

このプロジェクトには、"Xbox 360 Bundle"、"Xbox 360"、および "Kinect" という 3 つのアイテムを表す 3 つのコンテンツ タイプが必要です。このシナリオでは、アイテムのタイトルのみが必要なので、それぞれのコンテンツ タイプは "アイテム" コンテンツ タイプを継承するだけでよく、フィールドの追加は不要です。

"Xbox 360 Bundle" コンテンツ タイプに基づく新しいアイテムが追加されたときは、そのアイテムを削除するか、追加を取り消した後、"Xbox 360" コンテンツ タイプと "Kinect" コンテンツ タイプに基づく 2 つのアイテムを作成する必要があります。

これを行うには、まず、ItemAdding という Before イベントを "Xbox 360 Bundle" コンテンツ タイプにバインドします。ItemAdding イベントで、2 つの別のアイテムを作成し、現在のアイテムの追加を取り消します。"Xbox 360" アイテムまたは "Kinect" アイテムが追加されたときにはこのロジックを開始する必要がないので、それらのコンテンツ タイプにはこのイベント レシーバーはバインドしません。簡潔にする便宜上、アイテムのコンテンツ タイプが "Xbox 360" から "Xbox 360 Bundle" または "Kinect" に変更される更新の処理は、ここでは省略します。

"Xbox 360 Bundle" コンテンツ タイプの追加を取り消すとき、エラー メッセージが発生しないようにする必要があります。追加されるアイテムには、Before イベントで (つまり、変更がコンテンツ データベースで確定される前の時点で) アクセスするので、その時点の properties.ListItem プロパティは null のままになっています。アイテム フィールドにアクセスするには、properties.AfterProperties プロパティ バッグを使用する必要があります。これを使用すると、リスト スキーマ内のフィールドの内部名に基づいて、コピーするデータ (この例ではタイトルのみ) にアクセスできます。

実装

空の SharePoint プロジェクト テンプレートに基づいて Visual Studio 2010 プロジェクトを作成します。ソリューションをサンドボックスとして展開することを選択します。プロジェクトを右クリックし、[新しい項目の追加] をクリックします。[コンテンツ タイプ] を選択し、追加する項目に「Xbox360Bundle」という名前を指定し、[追加] をクリックします。Visual Studio によって、"<プロジェクト名> - Xbox360Bundle" という名前のコンテンツ タイプが作成されます。

重要なメモ重要

Element.xml ファイルで、この名前を単なる「Xbox360Bundle」に変更してください。

他の 2 つのコンテンツ タイプについても同じ手順を繰り返し、それぞれ「Xbox360」および「Kinect」という名前を指定します。

次に、プロジェクトを右クリックし、「BundleEventReceiver」という名前の新しいイベント レシーバーを追加します。[アイテムが追加されています] を選択し、[完了] をクリックします。この手順によって、ItemAdding イベントをオーバーライドするイベント レシーバー クラスが作成されます。ただし、このイベントは既定でリスト テンプレートにバインドされます。ここでは、このイベントをリスト テンプレートではなく Xbox360Bundle コンテンツ タイプにバインドする必要があります。したがって、イベント バインド Elements.xml (図 9 で選択されているファイル) を削除し、Xbox360Bundle コンテンツ タイプの Element.xml 内にこのバインドを追加する必要があります。

図 9. Elements.xml バインド

Elements.xml のバインド

イベント レシーバー バインドを追加する前に、Elements.xml 内でコンテンツ タイプの Inherits 属性が TRUE ではなく FALSE に設定されていることを確認します。そうなっていないと、このイベント レシーバー バインドは機能しません。これによって継承を使用しなくなるので、すべてのフィールド参照を独自に定義する必要があります。そこで、Title フィールドへのフィールド参照を追加します。Xbox360Bundle コンテンツ タイプの Element.xml は次のようになります。

<Elements xmlns="https://schemas.microsoft.com/sharepoint/">
  <!-- Parent ContentType: Item (0x01) -->
  <ContentType ID="0x01004497ac28eb9a47fbabee43f48c3f5973"
               Name="Xbox360Bundle"
               Group="Custom Content Types"
               Description="My Content Type"
               Inherits="FALSE"
               Version="0">
    <FieldRefs>
      <FieldRef ID="{fa564e0f-0c70-4ab9-b863-0177e6ddd247}" 
                Name="Title" 
                Required="TRUE" 
                ShowInNewForm="TRUE" 
                ShowInEditForm="TRUE"/>
    </FieldRefs>
    <XmlDocuments>
      <XmlDocument NamespaceURI="https://schemas.microsoft.com/sharepoint/events">
        <spe:Receivers xmlns:spe="https://schemas.microsoft.com/sharepoint/events">
          <Receiver>
            <Name>Item Adding Event</Name>
            <Type>ItemAdding</Type>
            <Assembly>$SharePoint.Project.AssemblyFullName$</Assembly>
            <Class>ItemSplitting.BundleEventReceiver.BundleEventReceiver</Class>
            <SequenceNumber>10000</SequenceNumber>
          </Receiver>
        </spe:Receivers>
      </XmlDocument>
    </XmlDocuments>
  </ContentType>
</Elements>

ここで、BundleEventReceiver.cs ファイルに移動し、ItemAdding イベントにコードを追加し、そのコードで、Xbox360Bundle アイテムの追加を取り消し、Xbox360 コンテンツ タイプと Kinect コンテンツ タイプに基づく 2 つの新しいアイテムを作成します。

public override void ItemAdding(SPItemEventProperties properties)
{
    // Get a reference to the current list.
    SPList list = properties.List;

    // Get the "Xbox360" content type.
    SPContentType xboxContentType = list.ContentTypes["XBox360"];

    // Get the "Kinect" content type.
    SPContentType kinectContentType = list.ContentTypes["Kinect"];

    // If any of the content types are null, they were not created.
    if (xboxContentType == null || kinectContentType == null)
    {
        properties.Status = SPEventReceiverStatus.CancelWithError;
        properties.ErrorMessage = "The Xbox360 and Kinect content types must be present.";
        return;
    }

    // Disable event firing so that ItemAdding is not called recursively.
    this.EventFiringEnabled = false;

    // Create the "Xbox360" item.
    SPListItem xboxItem = list.AddItem();
    xboxItem["Title"] = properties.AfterProperties["Title"] + " (Xbox 360)";
    xboxItem["ContentTypeId"] = xboxContentType.Id;
    xboxItem.Update();

    // Create the "Kinect" item.
    SPListItem kinectItem = list.AddItem();
    kinectItem["Title"] = properties.AfterProperties["Title"] + " (Kinect)";
    kinectItem["ContentTypeId"] = kinectContentType.Id;
    kinectItem.Update();

    // Re-enable event firing.
    this.EventFiringEnabled = true;

    // Cancel the creation of the "Xbox360Bundle" item but don't throw an error.
    properties.Status = SPEventReceiverStatus.CancelNoError;
}

このコードの次の点に注目してください。

  • リストにコンテンツ タイプがバインドされていない場合は、ItemAdding イベントを取り消し、"The Xbox360 and Kinect content types must be present."(Xbox360 コンテンツ タイプと Kinect コンテンツ タイプが存在する必要があります。) というエラー メッセージを表示します。properties.Cancel = true というステートメントを追加する必要はありません。

  • ItemAdding でそれ自体が (コール スタックの上限に達するまで) 再帰的に呼び出されるのを防ぐために、ItemAdding イベントでアイテムを追加する前にイベントの発生を無効にします。すべてのアイテムを追加した後、イベントの発生を有効に戻します。

  • ItemAdding は Before イベントであり、この時点ではリスト アイテムはまだ作成されておらず、properties.ListItem は null なので、ここでは、properties.ListITem["field"] ではなく properties.AfterProperties["field"] を使用します。

  • 分割するアイテムは追加する必要のないアイテムです。したがって、properties.Status = SPEventReceiverStatus.CancelNoError というステートメントを使用して、エラーをスローせずにイベントを取り消します。properties.Cancel=true を使用すると、動作がオーバーライドされてエラーがスローされるので、これは使用しません。

ここまで準備できたら、ソリューションをビルドし、デバッガーを開始できます。この操作によって、ソリューションが作成され、SharePoint サイト コレクションに展開され、サイト コレクションのホーム ページでブラウザーが起動されます。

次に、新しいリストを作成し、3 つのコンテンツ タイプをバインドします。まず、コンテンツ タイプをリストに追加できるようにします。これを行うには、リストの詳細設定ページで [コンテンツ タイプの管理を許可する] を [はい] に設定します。次に、図 10 のように、3 つのコンテンツ タイプを追加します。

図 10. コンテンツ タイプのバインド

バインド コンテンツ タイプ

これで、Xbox360Bundle コンテンツ タイプに基づいて、図 11 のように新しいアイテムをリストに作成できます。

図 11. 新しいアイテムの作成

新しいアイテムの追加

[保存] をクリックし、作成したアイテムが追加されていないことを確認します。代わりに、Xbox360 と Kinect という 2 つの別のアイテムが追加されます。リストから Xbox360 コンテンツ タイプまたは Kinect コンテンツ タイプを削除すると、保存時にエラー メッセージが表示されます。

例 3: ドキュメントのソースの追跡

イベント レシーバーを使用してドキュメントのプロパティを操作すると、強力な機能を追加できます。この例では、イベント レシーバーにプロパティの昇格と降格を実装してこれを行う方法を示します。プロパティの昇格と降格を使用すると、ドキュメント ライブラリにドキュメントを追加するとき、またはドキュメント ライブラリ内のドキュメントを編集するときに、イベント レシーバー コードでドキュメントのメタデータを直接読み取り、追加、および更新できます。

この例では、ドキュメント編集時に Source メタデータ プロパティの値をドキュメント ライブラリのタイトルに設定します。

クリックしてコードを取得コード サンプルのダウンロード: SharePoint 2010: Using Event Receivers, Example 3: Tracking Document Sources (英語)

デザイン

この例では、サイト内のすべてのドキュメント ライブラリにバインドする ItemUpdating イベント レシーバーを作成します。ドキュメント ライブラリにドキュメントを保存すると、イベント ハンドラー コードによって、Source メタデータ プロパティがドキュメント ライブラリのタイトルの値で追加または更新されます。

この動作をテストするには、2 つのドキュメント ライブラリを作成し、それぞれに Source フィールドを追加します。次に、一方のドキュメント ライブラリに Microsoft Word 文書をアップロードし、保存します。次に、この Word 文書をダウンロードし、Word クライアントを使用してメタデータを調べてから、もう 1 つのドキュメント ライブラリにこの文書をアップロードします。アップロード時には、Source フィールドの値は最初にアップロードしたドキュメント ライブラリのタイトルのままです。ただし、その文書を新しいドキュメント ライブラリに保存すると、Source プロパティの値は新しいドキュメント ライブラリのタイトルに変わります。新しく保存したドキュメントのメタデータを調べて、正しい結果になっているかどうか確認します。

実装

以下のコードは ItemUpdating イベントを実装します。

public override void ItemUpdating(SPItemEventProperties properties)
{
    string fieldInternalName = properties.List.Fields["Source"].InternalName;
    properties.AfterProperties[fieldInternalName] = properties.ListTitle;
}

ソリューションをビルドし、デバッガーを開始します。これらの操作では、ソリューションの作成、SharePoint サイト コレクションへの展開、サイト コレクションのホーム ページでのブラウザーの起動に必要な処理がすべて行われます。

新しいドキュメント ライブラリを作成し、Source フィールドを追加します。このフィールドを追加するには、ドキュメント ライブラリの設定へ移動し、[サイト内の既存の列から追加] をクリックし、Source フィールドを選択し、[追加]、[OK] の順にクリックします。

次に、そのドキュメント ライブラリに Word 文書をアップロードします。Source フィールドの値が空であることを確認します。[保存] をクリックすると、Source フィールドの値がドキュメント ライブラリのタイトルに変わります。

その文書をローカル コンピューターにダウンロードします。新しいドキュメント ライブラリを作成し、Source フィールドを追加します。この新しいドキュメント ライブラリに文書をアップロードします。アップロード時には、Source フィールドの値はドキュメントを最後に保存したドキュメント ライブラリのタイトルのままになっています。

次に、[Save] をクリックします。Source フィールドの値は、新しいドキュメント ライブラリのタイトルに変わります。

例 4: 取り消しとリダイレクト

この例では、(エラーまたはその他の理由で) ユーザー操作を取り消し、カスタムのエラー ページへリダイレクトします。

クリックしてコードを取得コード サンプルのダウンロード: SharePoint 2010: Using Event Receivers, Example 4: Canceling and Redirecting (英語)

デザイン

この例では、WebMoving イベントに Web イベント レシーバーを作成し、サイト URL の名前変更操作を取り消して [サイトの設定] ページにリダイレクトするコードを追加します ([サイトの設定] ページを使用するのはこの例を簡潔にするためです。実際にはカスタムのエラー メッセージ ページにリダイレクトできます)。

実装

SharePoint 2010 イベント レシーバー プロジェクト テンプレートに基づいて、Visual Studio 2010 プロジェクトを作成します。ソリューションをサンドボックスとして展開することを選択します。カスタマイズ ウィザードで、イベント ソースとして [Web イベント]、イベントとして [サイトが移動されています] を選択します。フィーチャーのスコープをサイトに変更します。

次のように、名前変更イベントを取り消し、[サイトの設定] ページにリダイレクトするコードを追加します。

public override void WebMoving(SPWebEventProperties properties)
{
    properties.Status = SPEventReceiverStatus.CancelWithRedirectUrl;
    properties.RedirectUrl = properties.Web.ServerRelativeUrl +
      "/_layouts/settings.aspx";
}

ソリューションをビルドし、デバッガーを開始します。これによって、ソリューションの作成、SharePoint サイト コレクションへの展開、サイト コレクションのホーム ページでのブラウザーの起動に必要な処理がすべて行われます。

次に、サブサイトを作成し、名前の変更を試行します (新しいサブサイトを作成する必要があるのは、ルート サイトは名前変更できないからです)。サイトを名前変更するために、[サイトの設定] ページへ移動します。[外観] セクションで、[タイトル、説明、アイコン] をクリックします。[URL 名] ボックスに新しいサイト名を入力します。[OK] をクリックします。

サイトの名前変更は失敗し、[サイトの設定] ページへリダイレクトされます。

例 5: イベントのログ記録

この例では、イベントを記録するコードを使用して、サイト コレクションで発生するすべてのイベントを検出し、各イベントをそのサイトで管理されるリストのアイテムとして記録するシナリオを示します。

クリックしてコードを取得コード サンプルのダウンロード: SharePoint 2010: Using Event Receivers, Example 5: Logging Events (英語)

デザイン

表 5 は、すべての SharePoint イベントおよび各イベントを記録するログ リストを示します。SiteDeleting イベントと SiteDeleted イベントは、サイト コレクションが削除されるときに発生するので、この例では記録しません。

表 5. イベントおよびログ

イベント

クラス

ログ リスト

SiteDeleting、SiteDeleted

SPWebEventReceiver

[記録しない]

WebAdding、WebProvisioned、WebDeleting、WebDeleted、WebMoving、WebMoved

SPWebEventReceiver

WebEventLogger

ListAdding、ListAdded、ListDeleting、ListDeleted

SPListEventReceiver

ListEventLogger

EmailReceived

SPEmailEventReceiver

ListEventLogger

FieldAdding、FieldAdded、FieldUpdating、FieldUpdated、FieldDeleting、FieldDeleted

SPListEventReceiver

ListEventLogger

ItemAdding、ItemAdded、ItemUpdating、ItemUpdated、ItemDeleting、ItemDeleted、ItemCheckingIn、ItemCheckedIn、ItemCheckingOut、ItemCheckedOut、ItemFileMoving、ItemFileMoved、ItemFileConverted、ItemAttachmentAdding、ItemAttachmentAdded、ItemAttachmentDeleting、ItemAttachmentDeleted

SPItemEventReceiver

ListItemEventLogger

WorkflowStarting、WorkflowStarted、WorkflowCompleted、WorkflowPostponed

SPWorkflowEventReceiver

WorkflowEventLogger

この例では、SPEventReceiverBase を継承するすべてのクラスのすべてのイベント メソッドをオーバーライドします。また、ヘルパー メソッドが含まれる新しいクラスを Common.cs ファイルに作成します。次に、ユーザー操作が完了する前に当該リストが更新されるように、After イベントを同期としてバインドします。サイト コレクション内のすべてのサイトで発生するすべてのイベントを処理できるようにするために、イベント バインドを有効化するフィーチャーのスコープはサイト レベルにします。

実装

空の SharePoint プロジェクト テンプレートに基づいて Visual Studio 2010 プロジェクトを作成します。ソリューションをサンドボックスとして展開することを選択します。

表 6 のイベントの種類ごとに、プロジェクトを右クリックし、[追加] をクリックし、[新しいアイテム] をポイントし、[イベント レシーバー] をクリックします。表のとおりにイベントのプロパティを選択し、[完了] をクリックします。

表 6. 新しいイベント レシーバーのプロパティ

イベントの種類

項目

イベント

Web

なし

すべてのイベント

リスト

なし

すべてのイベント

リスト項目

カスタム リスト

コンテキスト イベントを除くすべてのイベント

リスト電子メール

カスタム リスト

すべてのイベント

リスト ワークフロー

カスタム リスト

すべてのイベント

(カスタム リストに限らず) すべてのリストで発生するすべてのリスト項目イベント、リスト電子メール イベント、およびリスト ワークフロー イベントを処理するには、<Receivers> 要素から ListTemplateId 属性を削除します (<Receivers ListTemplateId="100"> を単なる <Receivers> に変更します)。

既定では、After イベントは非同期です。ここでは、すべての After イベントを同期にする必要があるので、すべての Elements.xml ファイル内の各 <Receiver> 要素に含まれる <Synchronization> 要素の値を "Synchronous" に設定します。たとえば、WebDeleted イベントは次のようになります。

<Receiver>
  <Name>EventReceiver1WebDeleted</Name>
  <Type>WebDeleted</Type>
  <Assembly>$SharePoint.Project.AssemblyFullName$</Assembly>
  <Class>PTCEventLogger.EventReceiver1.EventReceiver1</Class>
  <SequenceNumber>10000</SequenceNumber>
  <Synchronization>Synchronous</Synchronization>
</Receiver>

サイト コレクション全体で発生するイベントを処理できるように、フィーチャーのスコープをサイトに変更します。新しいサブサイトを作成すると、サイト作成のイベントおよびそのサイトに追加されるその他すべての項目のイベントが発生することになるので注意してください。その結果、サンドボックス ソリューション内のリソースが大量に消費され、Web 作成失敗の原因になる可能性があります。そのような潜在的問題を回避するには、プロジェクトのプロパティの [サンドボックス ソリューション] を [False] に変更するか、フィーチャーのスコープを Web に戻す必要があります。

次に、プロジェクトに common という名前のクラスを追加し、Common.cs というファイルに保存します。このクラスに次の 3 つのヘルパー メソッドを追加します。

  • IsBeforeEvent   イベントが Before イベントと After イベントのどちらであるかを示します。

    /// <summary>
    /// Indicates whether an event is a Before event or an After event.
    /// </summary>
    /// <param name="eventType"></param>
    /// <returns></returns>
    private static bool IsBeforeEvent(SPEventReceiverType eventType)
    {
        return (eventType < SPEventReceiverType.ItemAdded) ? true : false;
    }
    
  • EnsureLogList   ログ リストが既に存在するかどうかを確認します。存在する場合は、そのリストへの参照を取得します。存在しない場合は、リストを作成し、そのリストへの参照を取得します。

    /// <summary>
    /// Ensures that the Logs list with the specified name is created.
    /// </summary>
    /// <param name="web"></param>
    /// <param name="listName"></param>
    /// <returns></returns>
    private static SPList EnsureLogList(SPWeb web, string listName)
    {
        SPList list = null;
        try
        {
            list = web.Lists[listName];
        }
        catch
        {
            // Create list.
            Guid listGuid = web.Lists.Add(listName, listName, SPListTemplateType.GenericList);
            list = web.Lists[listGuid];
            list.OnQuickLaunch = true;
    
            // Add the fields to the list.
            // No need to add "Title" because it is added by default.
            // We use it to set the event name.
            list.Fields.Add("Event", SPFieldType.Text, true);
            list.Fields.Add("Before", SPFieldType.Boolean, true);
            list.Fields.Add("Date", SPFieldType.DateTime, true);
            list.Fields.Add("Details", SPFieldType.Note, false);
    
            // Specify which fields to view.
            SPView view = list.DefaultView;
            view.ViewFields.Add("Event");
            view.ViewFields.Add("Before");
            view.ViewFields.Add("Date");
            view.ViewFields.Add("Details");
            view.Update();
    
            list.Update();
        }
    
        return list;
    }
    
  • LogEvent   指定したリストに新しいアイテムを作成し、そのアイテムにイベントの詳細を記録します。

    /// <summary>
    /// Log the event to the specified list.
    /// </summary>
    /// <param name="web"></param>
    /// <param name="listName"></param>
    /// <param name="eventType"></param>
    /// <param name="details"></param>
    public static void LogEvent(SPWeb web, string listName, SPEventReceiverType eventType, 
      string details)
    {
        SPList logList = Common.EnsureLogList(web, listName);
        SPListItem logItem = logList.Items.Add();
        logItem["Title"] = string.Format("{0} triggered at {1}", eventType, DateTime.Now);
        logItem["Event"] = eventType.ToString();
        logItem["Before"] = Common.IsBeforeEvent(eventType);
        logItem["Date"] = DateTime.Now;
        logItem["Details"] = details;
        logItem.Update();
    }
    

SPWebEventReceiverSPListEventReceiverSPEmailEventReceiverSPItemEventReceiverSPWorkflowEventReceiver のいずれかを継承するクラスごとに、対応するリストにイベント プロパティを記録する Log メソッドを作成する必要があります。また、オーバーライドするすべてのメソッドを、これらの Log メソッドを呼び出すように変更する必要があります。次のコード例は、各イベント レシーバーに行う変更を示しています。

  • SPWebEventReceiver   オーバーライドするイベントをすべて変更します。たとえば、あるイベントは次のように変更します。

    public override void WebProvisioned(SPWebEventProperties properties)
    {
        this.LogWebEventProperties(properties);
    }
    

    以下のコードのように Log メソッドを追加します。

    private void LogWebEventProperties(SPWebEventProperties properties)
    {
        // Specify the log list name.
        string listName = "WebEventLogger";
    
        // Create string builder object.
        StringBuilder sb = new StringBuilder();
    
        // Add properties that do not throw exceptions.
        sb.AppendFormat("Cancel: {0}\n", properties.Cancel);
        sb.AppendFormat("ErrorMessage: {0}\n", properties.ErrorMessage);
        sb.AppendFormat("EventType: {0}\n", properties.EventType);
        sb.AppendFormat("FullUrl: {0}\n", properties.FullUrl);
        sb.AppendFormat("NewServerRelativeUrl: {0}\n", properties.NewServerRelativeUrl);
        sb.AppendFormat("ParentWebId: {0}\n", properties.ParentWebId);
        sb.AppendFormat("ReceiverData: {0}\n", properties.ReceiverData);
        sb.AppendFormat("RedirectUrl: {0}\n", properties.RedirectUrl);
        sb.AppendFormat("ServerRelativeUrl: {0}\n", properties.ServerRelativeUrl);
        sb.AppendFormat("SiteId: {0}\n", properties.SiteId);
        sb.AppendFormat("Status: {0}\n", properties.Status);
        sb.AppendFormat("UserDisplayName: {0}\n", properties.UserDisplayName);
        sb.AppendFormat("UserLoginName: {0}\n", properties.UserLoginName);
        sb.AppendFormat("WebId: {0}\n", properties.WebId);
        sb.AppendFormat("Web: {0}\n", properties.Web);
    
        // Log the event to the list.
        this.EventFiringEnabled = false;
        Common.LogEvent(properties.Web, listName, properties.EventType, sb.ToString());
        this.EventFiringEnabled = true;
    }
    
  • SPListEventReceiver   オーバーライドするイベントをすべて変更します。たとえば、あるイベントは次のように変更します。

    public override void FieldAdded(SPListEventProperties properties)
    {
        this.LogListEventProperties(properties);
    }
    

    以下のコードのように Log メソッドを追加します。

    private void LogListEventProperties(SPListEventProperties properties)
    {
        // Specify the log list name.
        string listName = "ListEventLogger";
    
        // Create the string builder object.
        StringBuilder sb = new StringBuilder();
    
        // Add properties that do not throw exceptions.
        sb.AppendFormat("Cancel: {0}\n", properties.Cancel);
        sb.AppendFormat("ErrorMessage: {0}\n", properties.ErrorMessage);
        sb.AppendFormat("EventType: {0}\n", properties.EventType);
        sb.AppendFormat("FeatureId: {0}\n", properties.FeatureId);
        sb.AppendFormat("FieldName: {0}\n", properties.FieldName);
        sb.AppendFormat("FieldXml: {0}\n", properties.FieldXml);
        sb.AppendFormat("ListId: {0}\n", properties.ListId);
        sb.AppendFormat("ListTitle: {0}\n", properties.ListTitle);
        sb.AppendFormat("ReceiverData: {0}\n", properties.ReceiverData);
        sb.AppendFormat("RedirectUrl: {0}\n", properties.RedirectUrl);
        sb.AppendFormat("SiteId: {0}\n", properties.SiteId);
        sb.AppendFormat("Status: {0}\n", properties.Status);
        sb.AppendFormat("TemplateId: {0}\n", properties.TemplateId);
        sb.AppendFormat("UserDisplayName: {0}\n", properties.UserDisplayName);
        sb.AppendFormat("UserLoginName: {0}\n", properties.UserLoginName);
        sb.AppendFormat("WebId: {0}\n", properties.WebId);
        sb.AppendFormat("WebUrl: {0}\n", properties.WebUrl);
        sb.AppendFormat("Web: {0}\n", properties.Web);
        sb.AppendFormat("List: {0}\n", properties.List);
    
        // Add properties that might throw exceptions.
        try
        {
            sb.AppendFormat("Field: {0}\n", properties.Field);
        }
        catch (Exception e)
        {
            sb.AppendFormat("\nError accessing properties.Field:\n\n {0}", e);
        }
    
        // Log the event to the list.
        this.EventFiringEnabled = false;
        Common.LogEvent(properties.Web, listName, properties.EventType, sb.ToString());
        this.EventFiringEnabled = true;
    }
    
  • SPEmailEventReceiver   EmailReceived イベントを次のように変更します。

    public override void EmailReceived(SPList list, SPEmailMessage emailMessage, String receiverData)
    {
        // Specify the log list name.
        string listName = "ListEmailEventLogger";
    
        // Create the string builder object.
        StringBuilder sb = new StringBuilder();
    
        // Add the email message properties.
        sb.AppendFormat("From:\t {0}\n", emailMessage.Sender);
        sb.AppendFormat("To:\t {0}\n", emailMessage.Headers["To"]);
        sb.AppendFormat("Subject:\t {0}\n", emailMessage.Headers["Subject"]);
        sb.AppendFormat("Body:\t {0}\n", emailMessage.PlainTextBody);
    
        // Log the event to the list.
        Common.LogEvent(list.ParentWeb, listName, SPEventReceiverType.EmailReceived, sb.ToString());
    }
    
  • SPItemEventReceiver   オーバーライドするイベントをすべて変更します。たとえば、あるイベントは次のように変更します。

    public override void ItemAttachmentAdded(SPItemEventProperties properties)
    {
        this.LogItemEventProperties(properties);
    }
    Add the log method.
    private void LogItemEventProperties(SPItemEventProperties properties)
    {
        // Specify the log list name.
        string listName = "ListItemEventLogger";
    
        // Create the string builder object.
        StringBuilder sb = new StringBuilder();
    
        // Add properties that do not throw exceptions.
        sb.AppendFormat("AfterUrl: {0}\n", properties.AfterUrl);
        sb.AppendFormat("BeforeUrl: {0}\n", properties.BeforeUrl);
        sb.AppendFormat("Cancel: {0}\n", properties.Cancel);
        sb.AppendFormat("CurrentUserId: {0}\n", properties.CurrentUserId);
        sb.AppendFormat("ErrorMessage: {0}\n", properties.ErrorMessage);
        sb.AppendFormat("EventType: {0}\n", properties.EventType);
        sb.AppendFormat("ListId: {0}\n", properties.ListId);
        sb.AppendFormat("ListItemId: {0}\n", properties.ListItemId);
        sb.AppendFormat("ListTitle: {0}\n", properties.ListTitle);
        sb.AppendFormat("ReceiverData: {0}\n", properties.ReceiverData);
        sb.AppendFormat("RedirectUrl: {0}\n", properties.RedirectUrl);
        sb.AppendFormat("RelativeWebUrl: {0}\n", properties.RelativeWebUrl);
        sb.AppendFormat("SiteId: {0}\n", properties.SiteId);
        sb.AppendFormat("Status: {0}\n", properties.Status);
        sb.AppendFormat("UserDisplayName: {0}\n", properties.UserDisplayName);
        sb.AppendFormat("UserLoginName: {0}\n", properties.UserLoginName);
        sb.AppendFormat("Versionless: {0}\n", properties.Versionless);
        sb.AppendFormat("WebUrl: {0}\n", properties.WebUrl);
        sb.AppendFormat("Web: {0}\n", properties.Web);
        sb.AppendFormat("Zone: {0}\n", properties.Zone);
        sb.AppendFormat("Context: {0}\n", properties.Context);
    
        // Add properties that might throw exceptions.
        try
        {
            sb.AppendFormat("ListItem: {0}\n", properties.ListItem);
        }
        catch (Exception e)
        {
            sb.AppendFormat("\nError accessing properties.ListItem:\n\n {0}", e);
        }
    
        // Add AfterProperties property bag.
        sb.AppendFormat("AfterProperties: {0}\n", properties.AfterProperties);
        IEnumerator afterProperties = properties.AfterProperties.GetEnumerator();
        int i = 0;
        while (afterProperties.MoveNext())
        {
            DictionaryEntry entry = (DictionaryEntry)afterProperties.Current;
            sb.AppendFormat("[{0}]: ({1}, {2})\n", i++, entry.Key, entry.Value);
        }
        sb.AppendFormat("AfterProperties.ChangedProperties: {0}\n", 
          properties.AfterProperties.ChangedProperties);
        IEnumerator changedAfterProperties = 
          properties.AfterProperties.ChangedProperties.GetEnumerator();
        i = 0;
        while (changedAfterProperties.MoveNext())
        {
            DictionaryEntry entry = (DictionaryEntry)changedAfterProperties.Current;
            sb.AppendFormat("[{0}]: ({1}, {2})\n", i++, entry.Key, entry.Value);
        }
    
        // Add BeforeProperties property bag.
        sb.AppendFormat("BeforeProperties: {0}\n", properties.BeforeProperties);
        IEnumerator beforeProperties = properties.BeforeProperties.GetEnumerator();
        i = 0;
        while (beforeProperties.MoveNext())
        {
            DictionaryEntry entry = (DictionaryEntry)beforeProperties.Current;
            sb.AppendFormat("[{0}]: ({1}, {2})\n", i++, entry.Key, entry.Value);
        }
        sb.AppendFormat("BeforeProperties.ChangedProperties: {0}\n", 
          properties.BeforeProperties.ChangedProperties);
        IEnumerator changedBeforeProperties = 
          properties.BeforeProperties.ChangedProperties.GetEnumerator();
        i = 0;
        while (changedBeforeProperties.MoveNext())
        {
            DictionaryEntry entry = (DictionaryEntry)changedBeforeProperties.Current;
            sb.AppendFormat("[{0}]: ({1}, {2})\n", i++, entry.Key, entry.Value);
        }
    
        // Log the event to the list.
        this.EventFiringEnabled = false;
        Common.LogEvent(properties.Web, listName, properties.EventType, sb.ToString());
        this.EventFiringEnabled = true;
    }
    
  • SPWorkflowEventReceiver   オーバーライドするイベントをすべて変更します。たとえば、あるイベントは次のように変更します。

    public override void WorkflowStarting(SPWorkflowEventProperties properties)
    {
        this.LogWorkflowEventProperties(properties);
    }
    

    以下のコードのように Log メソッドを追加します。

    private void LogWorkflowEventProperties(SPWorkflowEventProperties properties)
    {
        // Specify the log list name.
        string listName = "WorkflowEventLogger";
    
        // Create the string builder object.
        StringBuilder sb = new StringBuilder();
    
        // Add properties that do not throw exceptions.
        sb.AppendFormat("AssociationData: {0}\n", properties.AssociationData);
        sb.AppendFormat("Cancel: {0}\n", properties.Cancel);
        sb.AppendFormat("CompletionType: {0}\n", properties.CompletionType);
        sb.AppendFormat("ErrorMessage: {0}\n", properties.ErrorMessage);
        sb.AppendFormat("EventType: {0}\n", properties.EventType);
        sb.AppendFormat("InitiationData: {0}\n", properties.InitiationData);
        sb.AppendFormat("InstanceId: {0}\n", properties.InstanceId);
        sb.AppendFormat("PostponedEvent: {0}\n", properties.PostponedEvent);
        sb.AppendFormat("ReceiverData: {0}\n", properties.ReceiverData);
        sb.AppendFormat("RedirectUrl: {0}\n", properties.RedirectUrl);
        sb.AppendFormat("RelativeWebUrl: {0}\n", properties.RelativeWebUrl);
        sb.AppendFormat("SiteId: {0}\n", properties.SiteId);
        sb.AppendFormat("Status: {0}\n", properties.Status);
        sb.AppendFormat("TerminatedByUserId: {0}\n", properties.TerminatedByUserId);
        sb.AppendFormat("WebUrl: {0}\n", properties.WebUrl);
    
        // Get activation properties.
        SPWorkflowActivationProperties activationProperties = properties.ActivationProperties;
        if (activationProperties != null)
        {
            sb.AppendFormat("ActivationProperties.AssociationData: {0}\n", 
              activationProperties.AssociationData);
            sb.AppendFormat("ActivationProperties.HistoryListId: {0}\n", 
              activationProperties.HistoryListId);
            sb.AppendFormat("ActivationProperties.HistoryListUrl: {0}\n", 
              activationProperties.HistoryListUrl);
            sb.AppendFormat("ActivationProperties.InitiationData: {0}\n", 
              activationProperties.InitiationData);
            sb.AppendFormat("ActivationProperties.ItemId: {0}\n", 
              activationProperties.ItemId);
            sb.AppendFormat("ActivationProperties.ItemUrl: {0}\n", 
              activationProperties.ItemUrl);
            sb.AppendFormat("ActivationProperties.ListId: {0}\n", 
              activationProperties.ListId);
            sb.AppendFormat("ActivationProperties.ListUrl: {0}\n", 
              activationProperties.ListUrl);
            sb.AppendFormat("ActivationProperties.Originator: {0}\n", 
              activationProperties.Originator);
            sb.AppendFormat("ActivationProperties.OriginatorEmail: {0}\n", 
              activationProperties.OriginatorEmail);
            sb.AppendFormat("ActivationProperties.SiteId: {0}\n", 
              activationProperties.SiteId);
            sb.AppendFormat("ActivationProperties.SiteUrl: {0}\n", 
              activationProperties.SiteUrl);
            sb.AppendFormat("ActivationProperties.TaskListId: {0}\n", 
              activationProperties.TaskListId);
            sb.AppendFormat("ActivationProperties.TaskListUrl: {0}\n", 
              activationProperties.TaskListUrl);
            sb.AppendFormat("ActivationProperties.TemplateName: {0}\n", 
              activationProperties.TemplateName);
            sb.AppendFormat("ActivationProperties.WebId: {0}\n", 
              activationProperties.WebId);
            sb.AppendFormat("ActivationProperties.WebUrl: {0}\n", 
              activationProperties.WebUrl);
            sb.AppendFormat("ActivationProperties.WorkflowId: {0}\n", 
              activationProperties.WorkflowId);
    
            // Add properties that might throw exceptions.
            try
            {
                sb.AppendFormat("ActivationProperties.Context: {0}\n", 
                  activationProperties.Context);
                sb.AppendFormat("ActivationProperties.HistoryList: {0}\n", 
                  activationProperties.HistoryList);
                sb.AppendFormat("ActivationProperties.Item: {0}\n", 
                  activationProperties.Item);
                sb.AppendFormat("ActivationProperties.List: {0}\n", 
                  activationProperties.List);
                sb.AppendFormat("ActivationProperties.OriginatorUser: {0}\n", 
                  activationProperties.OriginatorUser);
                sb.AppendFormat("ActivationProperties.Site: {0}\n", 
                  activationProperties.Site);
                sb.AppendFormat("ActivationProperties.TaskList: {0}\n", 
                  activationProperties.TaskList);
                sb.AppendFormat("ActivationProperties.Web: {0}\n", 
                  activationProperties.Web);
                sb.AppendFormat("ActivationProperties.Workflow: {0}\n", 
                  activationProperties.Workflow);
            }
            catch (Exception e)
            {
                sb.AppendFormat("\nError accessing ActivationProperties property:\n\n {0}", e);
            }
        }
        else
        {
            sb.AppendFormat("ActivationProperties is null\n");
        }
    
        // Log the event to the list.
        this.EventFiringEnabled = false;
        Common.LogEvent(properties.ActivationProperties.Web, listName, 
          properties.EventType, sb.ToString());
        this.EventFiringEnabled = true;
    }
    

まとめ

ここでは、SharePoint 2010 イベント モデル全体、イベント レシーバーの作成方法、およびイベント レシーバーを実装するプロジェクトの展開方法について説明しました (また、Visual Studio 2010 でイベント レシーバー プロジェクト テンプレートを使用すると多くの作業を省略できることも示しました)。実際の要件に応用できる実践的な例もいくつか紹介しました。SharePoint イベント モデルの詳細については、SharePoint 2010 SDK の「SharePoint Foundation 2010 のイベント」以降を参照してください。

その他の技術情報

詳細については、次のリソースを参照してください。