共用方式為


HOW TO:建立本身為 UI 的增益集

更新:2007 年 11 月

本範例示範如何建立本身為 Windows Presentation Foundation (WPF) 使用者介面 (UI) 並裝載在 WPF 獨立應用程式的增益集 (Add-In)。

此增益集是本身為 WPF 使用者控制項的 UI。這個使用者控制項的內容是單一按鈕,當按下時,會顯示訊息方塊。WPF 獨立應用程式會將增益集 UI 裝載為主應用程式視窗的內容。

必要條件

這個範例的重點是 .NET Framework 增益集模型實現此案例的 WPF 擴充,並假設下列項目:

範例

如需本主題隨附的完整範例,請參閱增益集為 UI 範例

範例

若要建立本身為 WPF UI 的增益集,每個管線區段、增益集和主應用程式都需要特定的程式碼。

實作合約管線區段

當增益集是 UI 時,增益集的合約必須實作 INativeHandleContract。範例中的 IWPFAddInContract 會實作 INativeHandleContract,如下列程式碼所示。

using System.AddIn.Contract; // INativeHandleContract
using System.AddIn.Pipeline; // AddInContractAttribute

namespace Contracts
{
    /// <summary>
    /// Defines the services that an add-in will provide to a host application.
    /// In this case, the add-in is a UI.
    /// </summary>
    [AddInContract]
    public interface IWPFAddInContract : INativeHandleContract {}
}

實作增益集檢視管線區段

因為增益集是實作為 FrameworkElement 型別的子類別,增益集檢視必須也是子類別 FrameworkElement。下列程式碼顯示合約的增益集檢視,實作為 WPFAddInView 類別。

using System.AddIn.Pipeline; // AddInBaseAttribute
using System.Windows.Controls; // UserControl

namespace AddInViews
{
    /// <summary>
    /// Defines the add-in's view of the contract.
    /// </summary>
    [AddInBase]
    public class WPFAddInView : UserControl { }
}

這裡的增益集檢視衍生自 UserControl。因此,增益集 UI 也應該衍生自 UserControl

實作增益集端配接器管線區段

雖然合約是 INativeHandleContract,但增益集是 FrameworkElement (如增益集檢視管線區段所指定)。因此,在跨越隔離界限之前,FrameworkElement 必須轉換為 INativeHandleContract。這個工作是由增益集端配接器藉由呼叫 ViewToContractAdapter 來執行的,如下列程式碼所示。

using System; // IntPtr
using System.AddIn.Contract; // INativeHandleContract
using System.AddIn.Pipeline; // AddInAdapterAttribute, FrameworkElementAdapters, ContractBase
using System.Security.Permissions;

using AddInViews; // WPFAddInView
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
    {
        WPFAddInView wpfAddInView;

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

        /// <summary>
        /// ContractBase.QueryContract must be overridden to:
        /// * Safely return a window handle for an add-in UI to the host 
        ///   application's application.
        /// * Enable tabbing between host application UI and add-in UI, in the
        ///   "add-in is a UI" scenario.
        /// </summary>
        public override IContract QueryContract(string contractIdentifier)
        {
            if (contractIdentifier.Equals(typeof(INativeHandleContract).AssemblyQualifiedName))
            {
                return FrameworkElementAdapters.ViewToContractAdapter(this.wpfAddInView);
            }

            return base.QueryContract(contractIdentifier);
        }

        /// <summary>
        /// GetHandle is called by the WPF add-in model from the host application's 
        /// application domain to to get the window handle for an add-in UI from the 
        /// add-in's application domain. GetHandle is called if a window handle isn't 
        /// returned by other means ie overriding ContractBase.QueryContract, 
        /// as shown above.
        /// NOTE: This method requires UnmanagedCodePermission to be called 
        ///       (full-trust by default), to prevent illegal window handle
        ///       access in partially trusted scenarios. If the add-in could
        ///       run in a partially trusted application domain 
        ///       (eg AddInSecurityLevel.Internet), you can safely return a window
        ///       handle by overriding ContractBase.QueryContract, as shown above.
        /// </summary>
        [SecurityPermissionAttribute(SecurityAction.Demand, Flags = SecurityPermissionFlag.UnmanagedCode)]
        public IntPtr GetHandle()
        {
            return FrameworkElementAdapters.ViewToContractAdapter(this.wpfAddInView).GetHandle();
        }
    }
}

在增益集傳回 UI 的增益集模型 (請參閱 HOW TO:建立傳回 UI 的增益集) 中,增益集配接器是藉由呼叫 ViewToContractAdapter,將 FrameworkElement 轉換為 INativeHandleContract。這個模型中也必須呼叫 ViewToContractAdapter,雖然您必須實作撰寫程式碼的方法以進行呼叫。如果呼叫 QueryContract 的程式碼預期為 INativeHandleContract,您可以藉由覆寫 QueryContract 和實作呼叫 ViewToContractAdapter 的程式碼來完成這項作業。在這個情況下,呼叫端是主應用程式端配接器,在接續的小節中涵蓋其說明。

注意事項:

在這個模型中,您也需要覆寫 QueryContract,才能夠在主應用程式 UI 和增益集 UI 間進行切換。如需詳細資訊,請參閱 Windows Presentation Foundation 增益集概觀中的<WPF 增益集限制>。

因為增益集端配接器會實作衍生自 INativeHandleContract 的介面,您也需要實作 GetHandle,雖然這在覆寫 QueryContract 時會被忽略。

實作主應用程式檢視管線區段

在這個模型中,主應用程式通常會預期主應用程式檢視是 FrameworkElement 子類別。在 INativeHandleContract 跨越隔離界限之後,主應用程式端配接器必須將 INativeHandleContract 轉換為 FrameworkElement。因為主應用程式沒有要呼叫方法以取得 FrameworkElement,主應用程式檢視必須藉由包含 FrameworkElement 以「傳回」該項目。因此,主應用程式檢視必須衍生自可以包含其他 UI 的 FrameworkElement 的子類別,例如 UserControl。下列程式碼顯示合約的主應用程式檢視,實作為 WPFAddInHostView 類別。

using System.Windows.Controls; // UserControl

namespace HostViews
{
    /// <summary>
    /// Defines the host's view of the add-in
    /// </summary>
    public class WPFAddInHostView : UserControl { }
}

實作主應用程式端配接器管線區段

雖然合約是 INativeHandleContract,但主應用程式必須有 UserControl (如主應用程式檢視所指定)。因此,在跨越隔離界限之後,在設定為主應用程式檢視 (衍生自 UserControl) 的內容之前,INativeHandleContract 必須轉換為 FrameworkElement

這個工作是由主應用程式端配接器來執行的,如下列程式碼所示。

using System.AddIn.Contract; // INativeHandleContract
using System.AddIn.Pipeline; // HostAdapterAttribute, FrameworkElementAdapters, ContractHandle
using System.Windows; // FrameworkElement

using Contracts; // IWPFAddInContract
using HostViews; // WPFAddInHostView

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

        public WPFAddIn_ContractToViewHostSideAdapter(IWPFAddInContract wpfAddInContract)
        {
            // Adapt the contract (IWPFAddInContract) to the host application's
            // view of the contract (WPFAddInHostView)
            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);

            // Convert the INativeHandleContract for the add-in UI that was passed 
            // from the add-in side of the isolation boundary to a FrameworkElement
            string aqn = typeof(INativeHandleContract).AssemblyQualifiedName;
            INativeHandleContract inhc = (INativeHandleContract)wpfAddInContract.QueryContract(aqn);
            FrameworkElement fe = (FrameworkElement)FrameworkElementAdapters.ContractToViewAdapter(inhc);

            // Add FrameworkElement (which displays the UI provided by the add-in) as
            // content of the view (a UserControl)
            this.Content = fe;
        }
    }
}

如您所見,主應用程式端配接器藉由呼叫增益集端配接器的 QueryContract 方法 (這是 INativeHandleContract 跨越隔離界限的地方),取得 INativeHandleContract

接著,主應用程式端配接器藉由呼叫 ContractToViewAdapter,將 INativeHandleContract 轉換為 FrameworkElement。最後,FrameworkElement 會設定為主應用程式檢視的內容。

實作增益集

隨著增益集端配接器和增益集檢視就定位後,增益集可以藉由衍生自增益集檢視來實作,如下列程式碼所示。

    <addInViews:WPFAddInView
    xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:addInViews="clr-namespace:AddInViews;assembly=AddInViews"
    x:Class="WPFAddIn1.AddInUI">

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

</addInViews:WPFAddInView>
using System.AddIn; // AddInAttribute
using System.Windows; // MessageBox, RoutedEventArgs

using AddInViews; // WPFAddInView

namespace WPFAddIn1
{
    /// <summary>
    /// Implements the add-in by deriving from WPFAddInView
    /// </summary>
    [AddIn("WPF Add-In 1")]
    public partial class AddInUI : WPFAddInView
    {
        public AddInUI()
        {
            InitializeComponent();
        }

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

您可以從這個範例看出這個模型一個有趣的優點:增益集開發人員只需要實作增益集 (因為它同時也是 UI),而不需要同時實作增益集類別和增益集 UI。

實作主應用程式

隨著主應用程式端配接器和主應用程式檢視的建立,主應用程式可以使用 .NET Framework 增益集模型開啟管線,以及取得增益集的主應用程式檢視。這些步驟顯示在下列程式碼中。

// 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(WPFAddInHostView), appPath);
AddInToken wpfAddInToken = addInTokens[0];
this.wpfAddInHostView = wpfAddInToken.Activate<WPFAddInHostView>(AddInSecurityLevel.Internet);

// Display add-in UI
this.addInUIHostGrid.Children.Add(this.wpfAddInHostView);

主應用程式使用一般的 .NET Framework 增益集模型程式碼以啟動增益集,該增益集會隱含傳回主應用程式檢視給主應用程式。主應用程式接續會從 Grid 顯示主應用程式檢視 (為 UserControl)。

用於處理增益集 UI 互動的程式碼是在增益集的應用程式定義域中執行的。這些互動包括下列項目:

這項活動完全與主應用程式隔離。

請參閱

工作

增益集為 UI 範例

概念

增益集概觀

Windows Presentation Foundation 增益集概觀