方法 : UI を返すアドインを作成する

この例では、ホスト WPF スタンドアロン アプリケーションに Windows Presentation Foundation (WPF) user interface (UI) を返すアドインを作成する方法を示します。

このアドインが返すUI は、WPF ユーザー コントロールです。 ユーザー コントロールの中身は単一のボタンで、クリックするとメッセージ ボックスを表示します。 このアドインは WPF スタンドアロン アプリケーションがホストし、アドインが返すユーザー コントロールをメイン アプリケーション ウィンドウのコンテンツとして表示します。

必要条件

この例では、このシナリオを実現する .NET Framework アドイン モデルの WPF 拡張機能に焦点を当てます。前提条件は次のとおりです。

  • パイプライン、アドイン、ホスト開発など、.NET Framework アドイン モデルについて知っていること。 これらの概念の詳細については、「アドインおよび拡張機能」を参照してください。 パイプライン、アドイン、およびホスト アプリケーションの実装例を示すチュートリアルについては、「チュートリアル : 拡張性のあるアプリケーションの作成」を参照してください。

  • .NET Framework アドイン モデルの WPF 拡張機能について知っていること。詳細については、「WPF アドインの概要」を参照してください。

使用例

WPF UI を返すアドインを作成するには、各パイプライン セグメント、アドイン、およびホスト アプリケーションに特定のコードが必要です。

コントラクト パイプライン セグメントの実装

UI を返すようにするには、メソッドはコントラクトで宣言し、その戻り値を INativeHandleContract 型にする必要があります。 次のコードではこれについて、IWPFAddInContract コントラクトの GetAddInUI メソッドによって示します。


Imports System.AddIn.Contract ' IContract, INativeHandleContract
Imports System.AddIn.Pipeline ' AddInContractAttribute

Namespace Contracts
    ''' <summary>
    ''' Defines the services that an add-in will provide to a host application
    ''' </summary>
    <AddInContract>
    Public Interface IWPFAddInContract
        Inherits IContract
        ' Return a UI to the host application
        Function GetAddInUI() As INativeHandleContract
    End Interface
End Namespace
using System.AddIn.Contract; // IContract, INativeHandleContract
using System.AddIn.Pipeline; // AddInContractAttribute

namespace Contracts
{
    /// <summary>
    /// Defines the services that an add-in will provide to a host application
    /// </summary>
    [AddInContract]
    public interface IWPFAddInContract : IContract
    {
        // Return a UI to the host application
        INativeHandleContract GetAddInUI();
    }
}

アドイン ビュー パイプライン セグメントの実装

アドインは UIs を実装するため、FrameworkElement のサブクラスとして提供します。IWPFAddInView.GetAddInUI に関連するアドイン ビューのメソッドは FrameworkElement 型の値を返す必要があります。 次のコードでは、コントラクトのアドイン ビューがインターフェイスとして実装されています。


Imports System.AddIn.Pipeline ' AddInBaseAttribute
Imports System.Windows ' FrameworkElement

Namespace AddInViews
    ''' <summary>
    ''' Defines the add-in's view of the contract
    ''' </summary>
    <AddInBase>
    Public Interface IWPFAddInView
        ' The add-in's implementation of this method will return
        ' a UI type that directly or indirectly derives from 
        ' FrameworkElement.
        Function GetAddInUI() As FrameworkElement
    End Interface
End Namespace
using System.AddIn.Pipeline; // AddInBaseAttribute
using System.Windows; // FrameworkElement

namespace AddInViews
{
    /// <summary>
    /// Defines the add-in's view of the contract
    /// </summary>
    [AddInBase]
    public interface IWPFAddInView
    {
        // The add-in's implementation of this method will return
        // a UI type that directly or indirectly derives from 
        // FrameworkElement.
        FrameworkElement GetAddInUI();
    }
}

アドイン側アダプター パイプライン セグメントの実装

コントラクト メソッドは INativeHandleContract を返しますが、アドインは FrameworkElement を返します (アドイン ビューの指定のとおり)。 したがって、FrameworkElement は、分離境界を越える前に INativeHandleContract に変換される必要があります。 この処理は、次のコードに示すように、アドイン側のアダプターで ViewToContractAdapter を呼び出して実行されます。


Imports System.AddIn.Contract ' INativeHandleContract
Imports System.AddIn.Pipeline ' AddInAdapterAttribute, FrameworkElementAdapters, ContractBase
Imports System.Windows ' FrameworkElement

Imports AddInViews ' IWPFAddInView
Imports Contracts ' IWPFAddInContract

Namespace AddInSideAdapters
    ''' <summary>
    ''' Adapts the add-in's view of the contract to the add-in contract
    ''' </summary>
    <AddInAdapter>
    Public Class WPFAddIn_ViewToContractAddInSideAdapter
        Inherits ContractBase
        Implements IWPFAddInContract
        Private wpfAddInView As IWPFAddInView

        Public Sub New(ByVal wpfAddInView As IWPFAddInView)
            ' Adapt the add-in view of the contract (IWPFAddInView) 
            ' to the contract (IWPFAddInContract)
            Me.wpfAddInView = wpfAddInView
        End Sub

        Public Function GetAddInUI() As INativeHandleContract Implements IWPFAddInContract.GetAddInUI
            ' Convert the FrameworkElement from the add-in to an INativeHandleContract 
            ' that will be passed across the isolation boundary to the host application.
            Dim fe As FrameworkElement = Me.wpfAddInView.GetAddInUI()
            Dim inhc As INativeHandleContract = FrameworkElementAdapters.ViewToContractAdapter(fe)
            Return inhc
        End Function
    End Class
End Namespace
using System.AddIn.Contract; // INativeHandleContract
using System.AddIn.Pipeline; // AddInAdapterAttribute, FrameworkElementAdapters, ContractBase
using System.Windows; // FrameworkElement

using AddInViews; // IWPFAddInView
using Contracts; // IWPFAddInContract

namespace AddInSideAdapters
{
    /// <summary>
    /// Adapts the add-in's view of the contract to the add-in contract
    /// </summary>
    [AddInAdapter]
    public class WPFAddIn_ViewToContractAddInSideAdapter : ContractBase, IWPFAddInContract
    {
        IWPFAddInView wpfAddInView;

        public WPFAddIn_ViewToContractAddInSideAdapter(IWPFAddInView wpfAddInView)
        {
            // Adapt the add-in view of the contract (IWPFAddInView) 
            // to the contract (IWPFAddInContract)
            this.wpfAddInView = wpfAddInView;
        }

        public INativeHandleContract GetAddInUI()
        {
            // Convert the FrameworkElement from the add-in to an INativeHandleContract 
            // that will be passed across the isolation boundary to the host application.
            FrameworkElement fe = this.wpfAddInView.GetAddInUI();
            INativeHandleContract inhc = FrameworkElementAdapters.ViewToContractAdapter(fe);
            return inhc;
        }
    }
}

ホスト ビュー パイプライン セグメントの実装

ホスト アプリケーションは FrameworkElement を表示するため、IWPFAddInHostView.GetAddInUI に関連するホスト ビューのメソッドは FrameworkElement 型の値を返す必要があります。 次のコードでは、コントラクトのホスト ビューがインターフェイスとして実装されています。


Imports System.Windows ' FrameworkElement

Namespace HostViews
    ''' <summary>
    ''' Defines the host's view of the add-in
    ''' </summary>
    Public Interface IWPFAddInHostView
        ' The view returns as a class that directly or indirectly derives from 
        ' FrameworkElement and can subsequently be displayed by the host 
        ' application by embedding it as content or sub-content of a UI that is 
        ' implemented by the host application.
        Function GetAddInUI() As FrameworkElement
    End Interface
End Namespace
using System.Windows; // FrameworkElement

namespace HostViews
{
    /// <summary>
    /// Defines the host's view of the add-in
    /// </summary>
    public interface IWPFAddInHostView
    {
        // The view returns as a class that directly or indirectly derives from 
        // FrameworkElement and can subsequently be displayed by the host 
        // application by embedding it as content or sub-content of a UI that is 
        // implemented by the host application.
        FrameworkElement GetAddInUI();
    }
}

ホスト側アダプター パイプライン セグメントの実装

コントラクト メソッドは INativeHandleContract を返しますが、ホスト アプリケーションでは FrameworkElement が想定されています (ホスト ビューの指定のとおり)。 したがって、INativeHandleContract は、分離境界を越えた後に FrameworkElement に変換される必要があります。 この処理は、次のコードに示されているように、ホスト側のアダプターで ContractToViewAdapter を呼び出して実行されます。


Imports System.AddIn.Contract ' INativeHandleContract
Imports System.AddIn.Pipeline ' HostAdapterAttribute, FrameworkElementAdapters, ContractHandle
Imports System.Windows ' FrameworkElement

Imports Contracts ' IWPFAddInContract
Imports HostViews ' IWPFAddInHostView

Namespace HostSideAdapters
    ''' <summary>
    ''' Adapts the add-in contract to the host's view of the add-in
    ''' </summary>
    <HostAdapter>
    Public Class WPFAddIn_ContractToViewHostSideAdapter
        Implements IWPFAddInHostView
        Private wpfAddInContract As IWPFAddInContract
        Private wpfAddInContractHandle As ContractHandle

        Public Sub New(ByVal wpfAddInContract As IWPFAddInContract)
            ' Adapt the contract (IWPFAddInContract) to the host application's
            ' view of the contract (IWPFAddInHostView)
            Me.wpfAddInContract = wpfAddInContract

            ' Prevent the reference to the contract from being released while the
            ' host application uses the add-in
            Me.wpfAddInContractHandle = New ContractHandle(wpfAddInContract)
        End Sub

        Public Function GetAddInUI() As FrameworkElement Implements IWPFAddInHostView.GetAddInUI
            ' Convert the INativeHandleContract that was passed from the add-in side
            ' of the isolation boundary to a FrameworkElement
            Dim inhc As INativeHandleContract = Me.wpfAddInContract.GetAddInUI()
            Dim fe As FrameworkElement = FrameworkElementAdapters.ContractToViewAdapter(inhc)
            Return fe
        End Function
    End Class
End Namespace
using System.AddIn.Contract; // INativeHandleContract
using System.AddIn.Pipeline; // HostAdapterAttribute, FrameworkElementAdapters, ContractHandle
using System.Windows; // FrameworkElement

using Contracts; // IWPFAddInContract
using HostViews; // IWPFAddInHostView

namespace HostSideAdapters
{
    /// <summary>
    /// Adapts the add-in contract to the host's view of the add-in
    /// </summary>
    [HostAdapter]
    public class WPFAddIn_ContractToViewHostSideAdapter : IWPFAddInHostView
    {
        IWPFAddInContract wpfAddInContract;
        ContractHandle wpfAddInContractHandle;

        public WPFAddIn_ContractToViewHostSideAdapter(IWPFAddInContract wpfAddInContract)
        {
            // Adapt the contract (IWPFAddInContract) to the host application's
            // view of the contract (IWPFAddInHostView)
            this.wpfAddInContract = wpfAddInContract;

            // Prevent the reference to the contract from being released while the
            // host application uses the add-in
            this.wpfAddInContractHandle = new ContractHandle(wpfAddInContract);
        }

        public FrameworkElement GetAddInUI()
        {
            // Convert the INativeHandleContract that was passed from the add-in side
            // of the isolation boundary to a FrameworkElement
            INativeHandleContract inhc = this.wpfAddInContract.GetAddInUI();
            FrameworkElement fe = FrameworkElementAdapters.ContractToViewAdapter(inhc);
            return fe;
        }
    }
}

アドインの実装

アドイン側のアダプターとアドイン ビューを作成したら、アドイン (WPFAddIn1.AddIn) に IWPFAddInView.GetAddInUI メソッドを実装して、FrameworkElement オブジェクト (この例では UserControl) を返すようにする必要があります。 UserControl (AddInUI) は次のコードに示すように実装します。

    <UserControl
    xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
    x:Class="WPFAddIn1.AddInUI">

    <StackPanel>
        <Button Click="clickMeButton_Click" Content="Click Me!" />
    </StackPanel>

</UserControl>

Imports System.Windows ' MessageBox, RoutedEventArgs
Imports System.Windows.Controls ' UserControl

Namespace WPFAddIn1
    Partial Public Class AddInUI
        Inherits UserControl
        Public Sub New()
            InitializeComponent()
        End Sub

        Private Sub clickMeButton_Click(ByVal sender As Object, ByVal e As RoutedEventArgs)
            MessageBox.Show("Hello from WPFAddIn1")
        End Sub
    End Class
End Namespace
using System.Windows; // MessageBox, RoutedEventArgs
using System.Windows.Controls; // UserControl

namespace WPFAddIn1
{
    public partial class AddInUI : UserControl
    {
        public AddInUI()
        {
            InitializeComponent();
        }

        void clickMeButton_Click(object sender, RoutedEventArgs e)
        {
            MessageBox.Show("Hello from WPFAddIn1");
        }
    }
}

アドインの IWPFAddInView.GetAddInUI の実装では、次のコードに示すように、AddInUI の新しいインスタンスを返すだけです。


Imports System.AddIn ' AddInAttribute
Imports System.Windows ' FrameworkElement

Imports AddInViews ' IWPFAddInView

Namespace WPFAddIn1
    ''' <summary>
    ''' Add-In implementation
    ''' </summary>
    <AddIn("WPF Add-In 1")>
    Public Class WPFAddIn
        Implements IWPFAddInView
        Public Function GetAddInUI() As FrameworkElement Implements IWPFAddInView.GetAddInUI
            ' Return add-in UI
            Return New AddInUI()
        End Function
    End Class
End Namespace
using System.AddIn; // AddInAttribute
using System.Windows; // FrameworkElement

using AddInViews; // IWPFAddInView

namespace WPFAddIn1
{
    /// <summary>
    /// Add-In implementation
    /// </summary>
    [AddIn("WPF Add-In 1")]
    public class WPFAddIn : IWPFAddInView
    {
        public FrameworkElement GetAddInUI()
        {
            // Return add-in UI
            return new AddInUI();
        }
    }
}

ホスト アプリケーションの実装

ホスト側のアダプターとホスト ビューが作成されると、ホスト アプリケーションで .NET Framework アドイン モデルを使用して、パイプラインを開き、アドインのビューを取得し、IWPFAddInHostView.GetAddInUI メソッドを呼び出すことができます。 これらの手順を次のコードに示します。

' Get add-in pipeline folder (the folder in which this application was launched from)
Dim appPath As String = Environment.CurrentDirectory

' Rebuild visual add-in pipeline
Dim warnings() As String = AddInStore.Rebuild(appPath)
If warnings.Length > 0 Then
    Dim msg As String = "Could not rebuild pipeline:"
    For Each warning As String In warnings
        msg &= vbLf & warning
    Next warning
    MessageBox.Show(msg)
    Return
End If

' Activate add-in with Internet zone security isolation
Dim addInTokens As Collection(Of AddInToken) = AddInStore.FindAddIns(GetType(IWPFAddInHostView), appPath)
Dim wpfAddInToken As AddInToken = addInTokens(0)
Me.wpfAddInHostView = wpfAddInToken.Activate(Of IWPFAddInHostView)(AddInSecurityLevel.Internet)

' Get and display add-in UI
Dim addInUI As FrameworkElement = Me.wpfAddInHostView.GetAddInUI()
Me.addInUIHostGrid.Children.Add(addInUI)
// Get add-in pipeline folder (the folder in which this application was launched from)
string appPath = Environment.CurrentDirectory;

// Rebuild visual add-in pipeline
string[] warnings = AddInStore.Rebuild(appPath);
if (warnings.Length > 0)
{
    string msg = "Could not rebuild pipeline:";
    foreach (string warning in warnings) msg += "\n" + warning;
    MessageBox.Show(msg);
    return;
}

// Activate add-in with Internet zone security isolation
Collection<AddInToken> addInTokens = AddInStore.FindAddIns(typeof(IWPFAddInHostView), appPath);
AddInToken wpfAddInToken = addInTokens[0];
this.wpfAddInHostView = wpfAddInToken.Activate<IWPFAddInHostView>(AddInSecurityLevel.Internet);

// Get and display add-in UI
FrameworkElement addInUI = this.wpfAddInHostView.GetAddInUI();
this.addInUIHostGrid.Children.Add(addInUI);

参照

概念

アドインおよび拡張機能

WPF アドインの概要