本範例示範如何建立可將 Windows Presentation Foundation (WPF) user interface (UI) 傳回主 WPF 獨立應用程式的增益集 (Add-In)。
此增益集所傳回的 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);