次の方法で共有


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

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

アドインは、WPF ユーザー コントロールである UI を返します。 ユーザー コントロールの内容は、クリックするとメッセージ ボックスを表示する 1 つのボタンです。 WPF スタンドアロン アプリケーションは、アドインをホストし、メイン アプリケーション ウィンドウのコンテンツとしてユーザー コントロール (アドインから返されます) を表示します。

前提条件

この例では、このシナリオを有効にする .NET Framework アドイン モデルへの WPF 拡張機能を強調表示し、次のことを前提としています。

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

  • .NET Framework アドイン モデルに対する WPF 拡張機能に関する知識。WPF Add-Ins の概要参照してください。

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

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

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

using System.AddIn.Contract;
using System.AddIn.Pipeline;

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();
    }
}

Imports System.AddIn.Contract
Imports System.AddIn.Pipeline

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

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

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

using System.AddIn.Pipeline;
using System.Windows;

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();
    }
}

Imports System.AddIn.Pipeline
Imports System.Windows

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

Add-In-Side アダプター パイプライン セグメントの実装を行う

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

using System.AddIn.Contract;
using System.AddIn.Pipeline;
using System.Windows;

using AddInViews;
using Contracts;

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;
        }
    }
}

Imports System.AddIn.Contract
Imports System.AddIn.Pipeline
Imports System.Windows

Imports AddInViews
Imports Contracts

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

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

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

using System.Windows;

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();
    }
}

Imports System.Windows

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

Host-Side アダプター パイプライン セグメントの実装

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

using System.AddIn.Contract;
using System.AddIn.Pipeline;
using System.Windows;

using Contracts;
using HostViews;

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;
        }
    }
}

Imports System.AddIn.Contract
Imports System.AddIn.Pipeline
Imports System.Windows

Imports Contracts
Imports HostViews

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

Add-In の実装

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

    <UserControl
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    x:Class="WPFAddIn1.AddInUI">
    
    <StackPanel>
        <Button Click="clickMeButton_Click" Content="Click Me!" />
    </StackPanel>
    
</UserControl>
using System.Windows;
using System.Windows.Controls;

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

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

Imports System.Windows
Imports System.Windows.Controls

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

アドインによる IWPFAddInView.GetAddInUI の実装では、次のコードに示すように、AddInUIの新しいインスタンスを返す必要があります。

using System.AddIn;
using System.Windows;

using AddInViews;

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();
        }
    }
}

Imports System.AddIn
Imports System.Windows

Imports AddInViews

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

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

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

// 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);
' 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)

こちらも参照ください