銀の光と碧い空

クラウドなインフラとC#なアプリ開発の狭間にいるエンジニアの日々

VSTO で WPF を使うには

Office アドイン Advent Calendar の8日目です。

www.adventar.org

VSTOでUIを作るのはWindows Formsの方が対応されてはいます。しかし、私を含めWindows デスクトップでGUI作成といえばWPFばかりやってきているので、WPFを使いたい!という人も多いと思います。そこで今日はWPFの画面をVSTOで使う方法を紹介したいと思います。

以前デモを行った、Wordのタスクペインに、Flickrの検索ボタンと画像を選択したらワードに挿入するというアプリを例に使います。

github.com

ポイントとしては、WPFのコントロールをUserControlとして作成するのですが、このときUserControlはVSTOのプロジェクトとは別のWPFカスタムコントロールライブラリプロジェクトとして作成しています。

f:id:tanaka733:20151206164657p:plain

必須ではないのですが、こうしておいた方がUserControlを作成するときのWPFに必要なクラスライブラリの選択が不要だったり、デフォルトでXAMLエディタが起動したりでなにかと楽になります。こうして、UserControlの画面を作成していきます。

次にポイントなるのが、VSTOとWPFでのやり取りになります。今回のケースでは、WPF側で画像をクリック => Wordにクリックされた画像を挿入するためにVSTOのメソッドを呼ぶ、という部分です。VSTOのプロジェクトはWPFのプロジェクトを参照するので、逆の流れ*1であれば、WPF側でメソッドを公開しておいて、それをVSTOが呼ぶということができます。そこでWPF側にイベントハンドラを公開し、VSTO側はそのイベントを購読するようにしました。

VSTOSample/UserControl1.xaml.cs at master · tanaka-takayoshi/VSTOSample · GitHub

VSTOSample/ThisAddIn.cs at master · tanaka-takayoshi/VSTOSample · GitHub

最後にWPFで作ったUserControlをタスクペインに追加する方法ですが、空のタスクペインを作成しておきロード時にElementHostを動的に追加し、そのElementHostUserControlを追加します。

private void MyTaskPane_Load(object sender, EventArgs e)
{
    var ehost = new ElementHost {Dock = DockStyle.Fill};
    MyControl = new UserControl1();
    ehost.Child = MyControl;
    Controls.Add(ehost);
}

追加したUserControlをプロパティで公開しているのは、前述の通りThisAddInからWPFとのやりとりを行うためです。

以上でVSTOでWPFが動かす基本的な内容になります。実際に動かすとこんな感じになります。

f:id:tanaka733:20151206173737g:plain

参考資料

*1:今回のケースでは画像挿入が完了したメッセージをSyncメソッドでWPF側に送っている