はじめに
エンタープライズ用アプリケーション開発のためのプラットフォームとしてさまざまな機能を提供する「Microsoft SharePoint Server」(以降、SharePoint)ではメインとなるアプリケーションがASP.NETで書かれています。SilverlightなどのRIA用プラットフォームが増えていく中で、SharePointでも、よりリッチな操作性やユーザーエクスペリエンスが求められていることは確かです。そこで今回は、NetAdvantage Silverlightを使用してSharePoint上でのSilverlightを活用する例をご紹介します。
対象読者
- SharePointアプリケーションおよびSharePoint上のWebサービスを使用するアプリケーションの開発者
- Visual Studio 2008およびExpression Blend 3を使ったSiverlightアプリケーションの開発者
- Microsoft SharePoint Server 2007あるいはWindows SharePoint Service 3.0上での開発者
本稿では、実装に必要なコードやスタイルの全ては記載しておりませんが、各工程で作成されるファイルが明記してありますので、付属のソースコードを参考に本稿をお読みください。
必要環境
- Microsoft Visual Studio 2008
- Microsoft Expression Blend 3
- Microsoft SharePoint Server 2007(以降、MOSS)あるいは Windows SharePoint Service 3.0(以降、WSS)
- NetAdvantage Silverlight 2009 vol. 1以降
本稿ではWindows SharePoint Service 3.0を使用し、すべてのコードをC#で書いています。また、NetAdvantage Silverlight 2009 vol. 1は開発環境にインストールする必要があります。
NetAdvantage Silverlightについて
「NetAdvantage Silverlight」はインフラジスティックス社のNetAdvantage for Web Clientに含まれる、業務アプリケーション向けのSilverlightコンポーネント集です。詳細についてはサイトまたはオンラインサンプルにてご確認ください。また、以前のリッチクライアント記事でもNetAdvantage Silverlightを紹介しています。
SharePointのカスタマイズ
標準のSharePoint Webアプリケーションでは検索ボックスにキーワードを入力する場所が画面右上に常に表示され、検索を行うと検索結果のページが表示されます。今回はSilverlightを利用してこの検索用インターフェイスをカスタマイズし、さらにNetAdvantage Silverlightコントロールの一つであるxamWebTileViewを使用して検索結果を表示します。


SharePoint用Silverlightアプリケーション開発について
Silverlightアプリケーションはxapファイルと呼ばれるアーカイブとしてユーザーの環境に配信されます。NetAdvantageのようなコンポーネントを使用する際にもxapファイルにすべてが含まれるため、MOSS/WSS上にNetAdvantageをインストールする必要はありません。
このため、開発時にはまずインターフェイスをExpression Blendでデザインし、Visual Studioで必要なコードを実装します。SharePointの検索機能はURLを介したWebサービスとして公開されているため、Visual Studio上では通常のWebサービス参照として扱うことが可能です。
完成したSilverlightアプリケーションのxapファイルをSharePointにデプロイするにはxapファイルの配置だけではなく、MOSS/WSS上でSilverlightを使用するためのWebアプリケーションの環境設定(web.configファイル)が必要です。詳細は「SharePointへのデプロイ」の項を参照してください。
検索インターフェイスの作成
検索キーワードの入力および検索実行用ボタンが配置されるパネルはSilverlight標準のStackPanelを使用します。ユーザーが検索機能を使用しない時にはパネルを縮小し、ユーザーが必要な時にキーワード入力部分が表示されるようにするようにします。

2つのStackPanelを使用したパネルはExpression Blendを使用して作成します。作成後のXAMLは以下のようになります。
<Grid HorizontalAlignment="Right" Width="300">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="auto"/>
</Grid.ColumnDefinitions>
<StackPanel x:Name="spnlSearchBox" Margin="0,0,0,0" HorizontalAlignment="Left"
VerticalAlignment="Stretch" Grid.Column="0" Width="250" Opacity="0.6">
<TextBlock Height="30" Width="164" Margin="6,30,80,0" VerticalAlignment="Top"
Text="キーワードを入力:" TextWrapping="Wrap" Foreground="Navy"
Opacity="1" FontSize="16" FontWeight="Bold" />
<TextBox x:Name="txtKeywords" Margin="4,0,8,8" Text="TextBox" TextWrapping="Wrap"
Opacity="1"/>
<Button Height="35" Margin="120,0,8,0" Content="検索"
Background="{StaticResource DarkBrush}" Opacity="1" Click="Button_Click"
FontSize="16" FontWeight="Bold"/>
</StackPanel>
<StackPanel x:Name="spnlToolbar" Width="50" Margin="0,0,0,0"
HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Grid.Column="1"
MouseLeftButtonDown="spnlToolbar_MouseLeftButtonDown"
MouseEnter="spnlToolbar_MouseEnter" MouseLeave="spnlToolbar_MouseLeave">
<TextBlock x:Name="textBlock" Margin="-37,50,-37,0" Text="Search"
TextWrapping="NoWrap" FontWeight="Bold" FontSize="32"
RenderTransformOrigin="0.5,0.5" UseLayoutRounding="False"
d:LayoutRounding="Auto" Height="49.545" Cursor="Hand"
ToolTipService.ToolTip="SharePointを検索">
<TextBlock.Foreground>
<LinearGradientBrush EndPoint="1.5,0" StartPoint="0,0">
<GradientStop Color="#FF4B920E"/>
<GradientStop Color="#FF458E06" Offset="1"/>
<GradientStop Color="#FF458E06"/>
</LinearGradientBrush>
</TextBlock.Foreground>
<TextBlock.RenderTransform>
<TransformGroup>
<ScaleTransform/>
<SkewTransform AngleX="0" AngleY="0"/>
<RotateTransform Angle="270"/>
<TranslateTransform/>
</TransformGroup>
</TextBlock.RenderTransform>
</TextBlock>
</StackPanel>
</Grid>
ユーザーが「Search」と書かれたテキストブロックをクリックした際のパネルの開閉処理はコードビハインドから行うため、ここではまだ実装しません(資料参照)。パネルの準備ができたら、今度はパネル上のマウスホバー時にユーザーにパネルがクリック可能であるというフィードバックを与えるため、このテキストブロックをハイライトさせるアニメーションを作成します。
Silverlightでアニメーションを用いるにはストーリーボードを作成します。[オブジェクトとタイムライン]タブ上で「Search」と書かれているテキストブロック(例:textBlock)をクリックし、適当な間隔のキーフレームを設定します。各キーフレームでは、テキストブロックのForegroundにハイライトとして使用されるGradientのGradientStopの位置を徐々にずらしていくことで、テキストブロックに表示されている文字列が左から右に光る効果が出せます。
★↓違いが一見して分かりにくいので、図5のキャプションで少し補足しました。


<Storyboard x:Name="sbSearch" RepeatBehavior="Forever">
<ColorAnimationUsingKeyFrames BeginTime="00:00:00"
Storyboard.TargetName="textBlock"
Storyboard.TargetProperty="(TextBlock.Foreground).(GradientBrush.
GradientStops)[0].(GradientStop.Color)">
<EasingColorKeyFrame KeyTime="00:00:00" Value="Black"/>
<EasingColorKeyFrame KeyTime="00:00:00.2000000" Value="#FF489009"/>
<EasingColorKeyFrame KeyTime="00:00:00.4000000" Value="#FF4F9413"/>
<EasingColorKeyFrame KeyTime="00:00:00.6000000" Value="#FF4B910E"/>
<EasingColorKeyFrame KeyTime="00:00:00.8000000" Value="#FF529617"/>
<EasingColorKeyFrame KeyTime="00:00:01.0000000" Value="#FF4B910E"/>
<EasingColorKeyFrame KeyTime="00:00:01.4800000" Value="#FF4B910E"/>
</ColorAnimationUsingKeyFrames>
ユーザーによるマウスオーバー操作とこのアニメーションを連動して開始するには、テキストブロックが配置されているパネルのMouseEnterおよびMouseLeaveイベントハンドラーでストーリーボードのBegin/Stopメソッドを呼ぶだけです。
private void spnlToolbar_MouseEnter(object sender, System.Windows.Input.MouseEventArgs e)
{
// "Search" のアニメーションを開始
this.sbSearch.Begin();
}
private void spnlToolbar_MouseLeave(object sender, System.Windows.Input.MouseEventArgs e)
{
// "Search" のアニメーションをストップ
this.sbSearch.Stop();
}
このようなささやかなアニメーションを使用したフィードバックもユーザーエクスペリエンスの向上には欠かせないものです。質の高いアニメーションを手軽に組み込むことができるのもSilverlightを使うメリットの一つと言えるでしょう。
検索結果インターフェイスの作成
xamWebDialogWindowとxamWebTileViewを使った
検索結果表示ウィンドウ
検索サービスを呼び出したら今度はサービスより返されるデータを処理し、表示することが必要です。今回はxamWebTileViewコントロールとxamWebDialogWindowを併用して検索結果を表示させます。
xamWebDialogWindowはSilverlightアプリケーション内で使用可能なダイアログウィンドウのコントロールです。ユーザーによる移動、縮小、最大化はもちろんのこと、モーダルダイアログとしても使用可能です。

検索結果表示用には別のユーザーコントロールを作成し、その中にxamWebDialogWindowを配置して使用するため、まずExpression Blendで新しいコントロールを追加し、その中にxamWebDialogWindowを配置します。
検索結果の表示にはxamWebTileViewコントロールを使用します。NetAdvantage Silverlightコントロールの一つであるxamWebTileViewではリスト上の各データをタイルとしてパネル表示し、各タイルはユーザーが任意に拡大・縮小および配置する動作を提供します。好きなように情報の配置を変更できることで、ユーザーは自分のタスク(検索、比較、詳細)に合った生産性を高めることが可能になります。xamWebTileViewについては以前のリッチクライアント記事でも紹介しています。

xamWebTileViewの使用にはコントロールをxamWebDialogWindow上にxamWebTileViewを配置し、検索結果のデータをバインドさせるだけです。

xamWebTileViewコントロールの表示用データは後ほど実装用コードより設定されるため、ここではItemSourceプロパティをResultという値にバインドしておきます。
<igDW:XamWebDialogWindow x:Name="xdwSearchWindow" HorizontalAlignment="Stretch"
VerticalAlignment="Stretch" Width="720" Height="560" Style="{StaticResource
XamWebDialogWindowStyle}">
<StackPanel>
<Grid x:Name="SearchOption" HorizontalAlignment="Left">
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<HyperlinkButton Grid.Column="0" Width="60">
<TextBlock Text="絞り込む" FontWeight="Bold" />
</HyperlinkButton>
<TextBox Grid.Column="1" x:Name="txtNarrowCriteria" Width="200"></TextBox>
<StackPanel x:Name="spnlNumFound" Orientation="Horizontal" Grid.Column="2"
Margin="10,0">
<TextBlock x:Name="txtNumFound" FontWeight="Bold" Foreground="#FFFF8C03"/>
<TextBlock x:Name="txtSearchStatus" HorizontalAlignment="Stretch"
Foreground="#FF98E60C"> 件 見つかりました</TextBlock>
</StackPanel>
</Grid>
<igTileView:XamWebTileView x:Name="xtvSearchResult" Margin="0,0,0,0"
ColumnsInPage="2" RowsInPage="3" Background="{x:Null}"
ItemsSource="{Binding Path=Result}"
TilePaneHeaderTemplate="{StaticResource SearchResultHeaderTemplate}"
TilePaneContainerStyle="{StaticResource TilePaneStyle}"
TilePaneContentTemplate="{StaticResource NormalPaneTemplate}"
MaximizedStateChanging="xtvSearchResult_MaximizedStateChanging">
<igTileView:XamWebTileView.TilePanelSettings>
<igTileView:TilePanelSettings MinimizedStripLocation="Right" AllowAnimation="True"
TilePaneTransition="Swap" />
</igTileView:XamWebTileView.TilePanelSettings>
</igTileView:XamWebTileView>
<Rectangle x:Name="recProgressIcon" Fill="{StaticResource IconBrush}"
StrokeThickness="0" Height="466" RenderTransformOrigin="0.5,0.5">
</Rectangle>
</StackPanel>
</igDW:XamWebDialogWindow>
検索パネルとの連動
検索処理部分を実装する前に、検索パネルのボタンクリックのイベントハンドラーを定義しておきます。Expression BlendよりVisual Studioを起動して記述するか、同じプロジェクトをVisual Studioから開けてイベントの定義を行います。xamDialogWindowは初期状態では表示されないため、WindowStateプロパティをHiddenに設定しておきます。
public partial class MainPage : UserControl
{
// 検索結果表示用ユーザーコントロール
SearchResult sr;
// 結果表示に使用される XamWebDialogWindow
XamWebDialogWindow win;
// 検索結果を格納する ViewModel
SPSearchResultDataSource viewModel;
// 検索キーワード入力用パネルが表示されているかのフラグ
bool panelOpen = false;
public MainPage()
{
InitializeComponent();
// 検索結果表示用ユーザーコントロールを追加
sr = new SearchResult();
this.LayoutRoot.Children.Add(sr);
// 初期状態では結果表示用の XamWebDialogWindow は非表示にしておく
win = (XamWebDialogWindow)sr.FindName("xdwSearchWindow");
win.WindowState = WindowState.Hidden;
// 初期状態ではこのコントロール自体を縮小表示
this.Width = 50;
this.spnlSearchBox.Visibility = Visibility.Collapsed;
}
検索結果を表示するxamDialogWindowを実際に表示させるのは、検索ボタンのClickイベントです。検索結果を保持するViewModelの準備および検索実行などのコードがありますが、それらについては後続のセクションで説明していきます。
private void Button_Click(object sender, System.Windows.RoutedEventArgs e)
{
win.IsModal = true;
win.CenterDialogWindow();
// 検索結果用 ViewModel を準備
this.viewModel = new SPSearchResultDataSource();
// XamWebDialogWindow 内に検索中のパネルを表示
sr.SwitchScreen(true, 0);
win.Show();
// 検索を実行
this.GetSearchResult();
}
これで検索パネルと結果表示用のダイアログウィンドウの準備が整いました。次に必要となるのはSharePoint Webサービスを使用した実際の検索処理です。
SharePoint検索Webサービスの使用
今回のアプリケーションでは実際の検索はSharePointの検索Webサービスに依存します。この検索機能はWebサービスとして公開されているため、アプリケーションで使用するSOAPクライアントを作成して使用します。
前のセクションでExpression Blendを使用して作成したプロジェクトを、今度はVisual Studioで開きます。
検索用Webサービスを使用するために、以下のような検索サービス用アドレス(.asmxファイルへのURL)をもとに、このサービスへの参照をVisual Studioのプロジェクトに追加します。
http://<サーバー名あるいはアドレス>/_vti_bin/spearch.asmx
アドレスを指定したサービスの参照ダイアログは以下のようになります。

追加されたサービス参照をアプリケーション内で使用するには、サービス用SOAPクライアントオブジェクトを作成し、クライアントのQueryExCompletedイベントハンドラーを実装します。
検索サービスを使用する際には実際にクエリとして使用されるXML文字列を送る必要があります。この文字列はQueryExAsyncメソッドを使用してクエリ用文字列(QueryPacket)を送信することで検索が実行されます。クエリ内では検索パネル内に入力された値をクエリのQueryText項目に追加します。今回使用されるクエリ文字列は以下のようになります。
string keywords = this.txtKeywords.Text; string qXMLString = "<QueryPacket xmlns='urn:Microsoft.Search.Query'>" + "<Query><SupportedFormats><Format revision='1'>" + "urn:Microsoft.Search.Response.Document:Document</Format>" + "</SupportedFormats><Context><QueryText language='ja-JP' type='STRING'>" + keywords + "</QueryText></Context></Query></QueryPacket>";
これでSharePointの検索Webサービスを呼び出す準備が整いました。SOAPクライアントを使用した検索処理は以下のようになります。
SharePointのクエリWebサービスの使用についてはMSDN「Windows SharePoint Serviceの検索アーキテクチャ」に詳細が記載されています。
private void GetSearchResult()
{
string keywords = this.txtKeywords.Text;
string qXMLString = "<QueryPacket xmlns='urn:Microsoft.Search.Query'>" +
"<Query><SupportedFormats><Format revision='1'>" +
"urn:Microsoft.Search.Response.Document:Document</Format>" +
"</SupportedFormats><Context><QueryText language='ja-JP' type='STRING'>" +
keywords + "</QueryText></Context></Query></QueryPacket>";
// 検索サービス用 SOAP クライアントを作成
SharePointSearch.SPSearch.QueryServiceSoapClient qsc = new SharePointSearch.SPSearch.QueryServiceSoapClient();
// サービス用認証情報を設定
// (使用する SharePoint サーバーのドメインアカウントを使用)
UserNamePasswordClientCredential upcc = qsc.ClientCredentials.UserName;
upcc.UserName = @"KALEHUAWEHE\Administrator";
upcc.Password = "Himitwo2";
// SPSearch Web サービスを使用
// QueyExCompleted イベントハンドラを設定
qsc.QueryExCompleted += new EventHandler<SharePointSearch.SPSearch.QueryExCompletedEventArgs>(qsc_QueryExCompleted);
// 検索用クエリを実行
qsc.QueryExAsync(qXMLString);
}
xamWebTileViewを使用した検索結果の表示
検索が終了した直後には非同期でQueryExCompletedイベントの発生が促されるため、このイベント用のハンドラーをあらかじめ定義しておくことが必要になります。
void qsc_QueryExCompleted(object sender, SharePointSearch.SPSearch.QueryExCompletedEventArgs e)
QueryExCompletedイベントハンドラーでは取得したデータを検索結果表示用xamWebTileViewコントロールのデータコンテキストに設定します(データコンテキストはすでにxamWebTileViewのItemSourceプロパティにバインドされるようにXAML上で設定されています)。これを実装するためには以下の手順が必要になります。
- 検索結果データ用オブジェクトの作成
- ViewModelの作成
- XMLドキュメントとして返されたデータを検索結果オブジェクトに変換
検索結果用データオブジェクトはSharePointの検索Webサービスから返されるデータをそのまま読み込めるようなオブジェクトを作成します(SPSearchRelevantResult.cs参照)。Silverlight 3ではADO.NETのDataSetなどが扱えませんが、その代わりにMVVM(Model-View-ViewModel)パターンで使用されるようなViewModelを作成してSilverlightのデータバインディング機能を活用することが一般的です。ここではSPSearchRelevantResultsオブジェクトをコレクションとして扱うViewModelを作成します。
MVVMパターンやViewModelについての詳しい説明はここでは割愛しますが、参考記事として以下のような記事へのリンクをあげておきます。興味のある方はご覧ください。
public class SPSearchResultDataSource : BaseViewModel
{
public SPSearchResultDataSource()
{
}
private IEnumerable<SPSearchRelevantResult> result;
public IEnumerable<SPSearchRelevantResult> Result
{
get
{
return this.result;
}
set
{
if (this.result != value)
{
this.result = value;
this.OnPropertyChanged("Result");
}
}
}
}
そして最後にXMLドキュメントとして返された検索結果をViewModel内のオブジェクトとしてセットします。作成したViewModelはxamWebTileViewのデータコンテキストとして設定することで、タイルビュー表示に使用されます。
検索中インターフェイスの作成
ユーザーに検索用インターフェイスへの入力をさせ、結果を表示させるアプリケーションはでき上がりましたが、SharePoint内のコンテンツの量やユーザーの環境によっては検索に時間がかかる場合もあります。検索パネルのアニメーションと同様に、ユーザーへのフィードバックをここでも追加することでユーザーエクスペリエンスを向上させることが可能です。

if (inProgress)
{
// 検索中のパネル(Rectangle)を表示
this.xtvSearchResult.Visibility = Visibility.Collapsed;
this.txtNumFound.Text = "";
this.txtSearchStatus.Text = "検索中...";
this.recProgressIcon.Visibility = Visibility.Visible;
this.sbProgress.Begin();
}
else
{
// 検索結果(xamWebTileView)を表示
this.xtvSearchResult.Visibility = Visibility.Visible;
this.recProgressIcon.Visibility = Visibility.Collapsed;
this.sbProgress.Stop();
this.txtNumFound.Text = numFound.ToString();
this.txtSearchStatus.Text = " 件のドキュメントが見つかりました。";
}
SharePointへのデプロイ
でき上がった検索用SilverlightアプリケーションをSharePoint Webアプリケーションにデプロイするには下記の準備が必要となります。
CLR 3.5の設定
Silverlightアプリケーションを実行するにはCLR 3.5の環境が必要となるため、Silverlightが使用できるように、SharePoint Webアプリケーションのweb.configファイルにCLR 3.5 ASP.NET AJAX Extensionの機能を追加する必要があります。この手順についての詳細は下記のいずれかの記事をご覧ください。
- MSDN Windows SharePoint Services Version 3.0にASP.NET 2.0 AJAX Extensions 1.0をインストールする
- SharePointでASP.NET AJAXを利用できるようにするには
MSDNの記事はASP.NET 2.0 AJAX Extensions 1.0用として書かれていますが、同じ手順をASP.NET 3.5用のアセンブリ参照に書き換えて適用することでSharePointアプリケーション上でSilverlightアプリケーションをホストするのに必要となるCLR 3.5用の環境設定が可能です。
CrossDomain.xmlとClientAccessPolicy.xml
SilverlightアプリケーションよりWebサービスを使用する際には、セキュリティ上の理由により、クロスドメインアクセスを許可する設定が必要になります。SilverlightランタイムはWebサービスなどのアクセス先にクロスドメインアクセスの情報が含まれるCrossDomain.xmlおよびClientAccessPolicy.xmlのどちらかのファイルがあるかを確認するため、これらのファイルをSilverlightアプリケーションがホストされるSharePoint Webアプリケーションに配置することが必要です。SharePointの場合、Office SharePoint Designerを使用してSilverlightアプリケーションを配布するサイトのルートフォルダに配置します。
ClientBinフォルダの設定
Silverlightアプリケーションは.xapファイルと呼ばれる形式で配布されますが、実際にこのファイルをホストするフォルダをSharePoint Webアプリケーション内(あるいはSharePointハイブ内)に作成する必要があります。フォルダの準備ができたら、Visual Studioでビルドされた検索用Silverlightアプリケーションの.xapファイルをコピーします。
MIMEタイプの設定
.xapファイルがSharePoint WebアプリケーションをホストするIISからSilverlightのアプリケーションとして正しくダウンロードされるようにするには、IISのMIMEタイプの設定に.xap拡張子がapplication/x-silverlight-appタイプとして認識されるように設定をする必要があります。
Silverlightアプリケーションをマスターページに埋め込む
最後に完成したSilverlightコントロールを埋め込むマスターページをOffice SharePoint Designerで編集します。SilverlightアプリケーションはHTMLページ上の<object>タグに埋め込まれるので、Visual Studioで作成したSilverlightアプリケーションのソリューションに追加されるWebアプリケーションのDefault.htmlページにならって、<object>タグをマスターページの任意の場所に追加します。
SharePoint WebアプリケーションはASP.NETのWebアプリケーションですので、通常の.aspxページと同じようにSilverlightアプリケーション配置用のタグを追加することが可能ですが、あらかじめ組み込まれているSharePoint用のタグを誤って消去してしまわないように注意してください。
<object data="data:application/x-silverlight-2," type="application/x-silverlight-2" width="800" height="600">
<param name="source" value="../../ClientBin/SharePointSearch.xap"/>
<param name="onerror" value="onSilverlightError" />
<param name="background" value="Transparent" />
<param name="width" value="800" />
<param name="height" value="600" />
<param name="windowLess" value="true" />
<param name="minRuntimeVersion" value="3.0.40624.0" />
<param name="autoUpgrade" value="true" />
<a href="http://go.microsoft.com/fwlink/?LinkID=149156&v=3.0.40624.0" style="text-decoration: none;">
<img src="http://go.microsoft.com/fwlink/?LinkId=108181" alt="Get Microsoft Silverlight" style="border-style: none"/>
</a>
</object>
まとめ
Webサービスとして使用可能なSharePoint上の機能はSilverlightでも簡単に使用することができます。今回はxamWebTileViewを使用しましたが、NetAdvantage Silverlightでは他にも多様なコントロールが提供されています。執筆時点でベータ版となっているSharePointの次期バージョンではSilverlight上でもSharePointオブジェクトが使用できるなど、Silverlightとの相互連携がさらに改善されるようですので、SharePoint上でのSilverlight活用はさらに広がりそうです。これを機にぜひトライしてみてはいかがでしょうか。

