Partilhar via


Como: Criar um suplemento que é uma interface do usuário

This example shows how to create an add-in that is a Windows Presentation Foundation (WPF) interface do usuário (UI) which is hosted by a WPF standalone application.

O suplemento é um UI Isto é um WPF controle de usuário. O conteúdo do controle de usuário é um único botão que, quando clicada, exibe uma caixa de mensagem. The WPF aplicativo autônomo hospeda o suplemento UI sistema autônomo o conteúdo da janela principal do aplicativo.

Pré-requisitos

Este exemplo realça o WPF extensões para o .NET Framework suplemento do modelo que permitem esse cenário e pressupõe o seguinte:

Exemplo

Para o exemplo completo que acompanha este tópico, consulte Adicionar-Em É um exemplo de interface do usuário.

Exemplo

To create an add-in that is a WPF UI requires specific code for each pipeline segment, the add-in, and the host application.

Implementando o segmento de pipeline do contrato

Quando um suplemento é um UI, o contrato para o suplemento deve implementar INativeHandleContract. No exemplo, IWPFAddInContract implementa INativeHandleContract, sistema autônomo mostra o código a seguir.

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

Implementando o segmento de Pipeline View de suplemento

Como o suplementos é implementado como uma subclasse do tipo FrameworkElement, a exibição do suplemento também deve ter como subclasse FrameworkElement. O seguinte código mostra a exibição do suplemento do contrato, implementado como a classe 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 { }
}

Aqui, a exibição do suplemento se origina do UserControl. Consequentemente, o suplemento UI também deve se originar do UserControl.

Implementando o suplemento-side adaptador pipeline segmento

Enquanto o contrato é um INativeHandleContract, o suplemento é um FrameworkElement (sistema autônomo especificado pelo add - no modo de exibição segmento de pipeline). Portanto, o FrameworkElement deve ser convertido em um INativeHandleContract antes de cruzar o limite de isolamento. O trabalho é executado pelo adaptador no lado do suplemento chamando ViewToContractAdapter, como exibido no código a seguir.

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

No suplemento modelo no qual um suplemento retorna um UI (consulte a Como: Criar um suplemento que retorna uma interface do usuário), adaptador suplementar convertido a FrameworkElement para um INativeHandleContract chamando ViewToContractAdapter. ViewToContractAdapter também deve ser chamado neste modelo, embora você precise implementar um método do qual escrever o código chamá-lo. Isso é feito substituindo QueryContract e implementando o código que chama ViewToContractAdapter se o código que está chamando QueryContract está esperando um INativeHandleContract. Nesse caso, o chamador será o adaptador do lado do host, que é tratado numa seção subsequente.

ObservaçãoObservação:

Você também precisa substituir QueryContract Neste modelo para habilitar a navegação por TAB entre o aplicativo host UI e suplemento UI. Para obter mais informações, consulte "WPF suplemento limitações" emVisão Geral dos Suplementos do Windows Presentation Foundation.

Como o adaptador no lado do suplemento implementa uma interface que deriva de INativeHandleContract, você também precisará implementar GetHandle, embora isso é ignorado quando QueryContract será substituída.

Implementando o segmento de pipeline exibir host

Nesse modelo, o aplicativo host tipicamente espera que o modo de host seja uma subclasse FrameworkElement. O adaptador do lado do host deve converter o INativeHandleContract em um FrameworkElement após o INativeHandleContract cruzar o limite de isolamento. Porque um método não está sendo chamado pelo aplicativo host para obter o FrameworkElement, a exibição do host deve "return" de FrameworkElement Por que o contém. Consequentemente, o modo de host deve se originar de uma subclasse de FrameworkElement que pode conter outro UIs tal como UserControl. O seguinte código mostra o modo de host do contrato, implementado como a classe WPFAddInHostView.

using System.Windows.Controls; // UserControl

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

Implementando o segmento de pipeline do adaptador no lado do host

Enquanto o contrato é um INativeHandleContract, o aplicativo host espera um UserControl (sistema autônomo especificado pela exibição do host). Consequentemente, o INativeHandleContract deve ser convertido em um FrameworkElement após cruzar o limite de isolamento, antes de ser definido como conteúdo do modo de host (que se origina do UserControl).

O trabalho é executado pelo adaptador do lado do host, como exibido no código a seguir.

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

sistema autônomo você pode ver, o adaptador do host adquire o INativeHandleContract chamando o adaptador no lado do suplemento QueryContract método (Este é o ponto em que o INativeHandleContract cruza o limite de isolamento).

Então, o adaptador do lado do host converte o INativeHandleContract em um FrameworkElement chamando ContractToViewAdapter. Finalmente, o FrameworkElement é definido como conteúdo do modo de host.

Implementando o Suplemento

Com o adaptador do lado do suplemento e a exibição do suplemento ajustados, o suplemento pode ser implementado sendo originado da exibição do suplemento, como mostrado no código a seguir.

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

Neste exemplo, você pode ver uma vantagem interessante desse modelo: sistema autônomo desenvolvedores de suplemento só precisam implementar o suplemento (sistema autônomo está o UI também), em vez de dois um add - na classe e um add - no UI.

Implementando o Aplicativo Host

Com o adaptador do host e a exibição do host criado, o aplicativo host pode usar o .NET Framework modelo suplementar para em em aberto o pipeline e adquirir um modo de exibição do host de suplemento. Esses passos são mostrados no seguinte código:

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

O aplicativo host utiliza um código de modelo de suplemento .NET Framework típico para ativar o suplemento, que implicitamente retorna o modo de host para o aplicativo host. O aplicativo host subsequentemente exibe o modo de host (que é um UserControl) a partir de um Grid.

O código para processar interações com o suplemento UI é executado no domínio de aplicativo do suplemento. Essas interações incluem o seguinte:

Esta atividade é completamente isolada do aplicativo host.

Consulte também

Tarefas

Adicionar-Em É um exemplo de interface do usuário

Conceitos

Adicionar-em Visão geral

Visão Geral dos Suplementos do Windows Presentation Foundation