Anteckning
Åtkomst till den här sidan kräver auktorisering. Du kan prova att logga in eller ändra kataloger.
Åtkomst till den här sidan kräver auktorisering. Du kan prova att ändra kataloger.
Det här exemplet visar hur du skapar ett tillägg som är en Windows Presentation Foundation (WPF) som hanteras av ett fristående WPF-program.
Tillägget är ett användargränssnitt som är en WPF-användarkontroll. Innehållet i användarkontrollen är en enda knapp som när du klickar visar en meddelanderuta. Det fristående WPF-programmet inrymmer tilläggets användargränssnitt som innehåll i huvudprogramfönstret.
Förutsättningar
I det här exemplet markeras WPF-tilläggen till .NET Framework-tilläggsmodellen som aktiverar det här scenariot och förutsätter följande:
Kunskap om .NET Framework-tilläggsmodellen, inklusive pipeline, tillägg och värdutveckling. Om du inte känner till de här begreppen, se Tillägg och Utökningsbarhet. För en handledning som visar implementeringen av en pipeline, ett tillägg och ett värdprogram, se Genomgång: Skapa ett utökningsbart program.
Kunskap om WPF-tilläggen till .NET Framework-tilläggsmodellen. Se ÖVERSIKT över WPF Add-Ins.
Exempel
För att skapa ett tillägg som är ett WPF-användargränssnitt krävs specifik kod för varje pipelinesegment, tillägget och värdprogrammet.
Implementera segmentet för kontraktspipeline
När ett tillägg är ett användargränssnitt måste kontraktet för tillägget implementera INativeHandleContract. I exemplet IWPFAddInContract implementerar INativeHandleContract, som du ser i följande kod.
using System.AddIn.Contract;
using System.AddIn.Pipeline;
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 {}
}
Imports System.AddIn.Contract
Imports System.AddIn.Pipeline
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
        Inherits INativeHandleContract
        Inherits IContract
    End Interface
End Namespace
Implementera Add-In Visa pipelinesegment
Eftersom tillägget implementeras som en subklass av FrameworkElement-typ, måste tilläggsvyn också vara en subklass av FrameworkElement. Följande kod visar tilläggsvyn för kontraktet, implementerat som WPFAddInView klassen.
using System.AddIn.Pipeline;
using System.Windows.Controls;
namespace AddInViews
{
    /// <summary>
    /// Defines the add-in's view of the contract.
    /// </summary>
    [AddInBase]
    public class WPFAddInView : UserControl { }
}
Imports System.AddIn.Pipeline
Imports System.Windows.Controls
Namespace AddInViews
    ''' <summary>
    ''' Defines the add-in's view of the contract.
    ''' </summary>
    <AddInBase>
    Public Class WPFAddInView
        Inherits UserControl
    End Class
End Namespace
Här här härleds tilläggsvyn från UserControl. Därför bör tilläggets användargränssnitt också härledas från UserControl.
Implementera Add-In-Side Adapter pipelinesegmentet
Även om kontraktet är ett INativeHandleContractär tillägget ett FrameworkElement (enligt vad som anges av pipelinesegmentet för tilläggsvyn). Därför FrameworkElement måste konverteras till en INativeHandleContract innan du passerar isoleringsgränsen. Det här arbetet utförs av tilläggssideadaptern genom att anropa ViewToContractAdapter, som visas i följande kod.
using System;
using System.AddIn.Contract;
using System.AddIn.Pipeline;
using System.Security.Permissions;
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
    {
        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 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, that is, 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>
        public IntPtr GetHandle()
        {
            return FrameworkElementAdapters.ViewToContractAdapter(this.wpfAddInView).GetHandle();
        }
    }
}
Imports System
Imports System.AddIn.Contract
Imports System.AddIn.Pipeline
Imports System.Security.Permissions
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 WPFAddInView
        Public Sub New(ByVal wpfAddInView As WPFAddInView)
            ' Adapt the add-in view of the contract (WPFAddInView) 
            ' to the contract (IWPFAddInContract)
            Me.wpfAddInView = wpfAddInView
        End Sub
        ''' <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 Overrides Function QueryContract(ByVal contractIdentifier As String) As IContract
            If contractIdentifier.Equals(GetType(INativeHandleContract).AssemblyQualifiedName) Then
                Return FrameworkElementAdapters.ViewToContractAdapter(Me.wpfAddInView)
            End If
            Return MyBase.QueryContract(contractIdentifier)
        End Function
        ''' <summary>
        ''' GetHandle is called by the WPF add-in model from the host application's 
        ''' application domain 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, that is, overriding ContractBase.QueryContract, 
        ''' as shown above.
        ''' </summary>
        Public Function GetHandle() As IntPtr Implements INativeHandleContract.GetHandle
            Return FrameworkElementAdapters.ViewToContractAdapter(Me.wpfAddInView).GetHandle()
        End Function
    End Class
End Namespace
I tilläggsmodellen där ett tillägg returnerar ett användargränssnitt (se Skapa en Add-In som returnerar ett användargränssnitt) konverterade tilläggskortet FrameworkElement till ett INativeHandleContract genom att anropa ViewToContractAdapter. ViewToContractAdapter måste också anropas i den här modellen, men du måste implementera en metod som du kan använda för att skriva koden för att anropa den. Du gör detta genom att åsidosätta QueryContract och implementera koden som anropar ViewToContractAdapter ifall den kod som anropar QueryContract förväntar sig en INativeHandleContract. I det här fallet är anroparen adaptern på värdsidan, som beskrivs i ett senare underavsnitt.
Anmärkning
Du måste också åsidosätta QueryContract i den här modellen för att aktivera tabbning mellan värdprogramsgränssnittet och tilläggsgränssnittet. Mer information finns i "WPF Add-In Begränsningar" i WPF Add-Ins Overview.
Eftersom add-in-side adaptern implementerar ett gränssnitt som härleds från INativeHandleContract, måste du också implementera GetHandle, även om detta ignoreras när QueryContract åsidosätts.
Implementera värdvyens pipeline-segment
I den här modellen förväntar sig värdprogrammet vanligtvis att värdvyn är en FrameworkElement underklass. Adaptern på värdsidan måste konvertera INativeHandleContract till en FrameworkElement efter att den INativeHandleContract korsat isoleringsgränsen. Eftersom värdprogrammet inte anropar en metod för att hämta FrameworkElement, måste värdvyn "returnera" FrameworkElement genom att innehålla den. Värdvyn måste därför härledas från en underklass av FrameworkElement som kan innehålla andra UIs, till exempel UserControl. Följande kod visar värdvyn för kontraktet, implementerad som WPFAddInHostView klassen.
using System.Windows.Controls;
namespace HostViews
{
    /// <summary>
    /// Defines the host's view of the add-in
    /// </summary>
    public class WPFAddInHostView : UserControl { }
}
Imports System.Windows.Controls
Namespace HostViews
    ''' <summary>
    ''' Defines the host's view of the add-in
    ''' </summary>
    Public Class WPFAddInHostView
        Inherits UserControl
    End Class
End Namespace
Implementering av Host-Side-adapterns pipelinesegment
Även om kontraktet är ett INativeHandleContractförväntar sig värdprogrammet en UserControl (enligt värdvyn). Därför INativeHandleContract måste konverteras till en FrameworkElement efter att ha korsat isoleringsgränsen, innan den anges som innehåll i värdvyn (som härleds från UserControl).
Det här arbetet utförs av nätverkskortet på värdsidan, enligt följande kod.
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 : 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;
        }
    }
}
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
        Inherits WPFAddInHostView
        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 (WPFAddInHostView)
            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)
            ' Convert the INativeHandleContract for the add-in UI that was passed 
            ' from the add-in side of the isolation boundary to a FrameworkElement
            Dim aqn As String = GetType(INativeHandleContract).AssemblyQualifiedName
            Dim inhc As INativeHandleContract = CType(wpfAddInContract.QueryContract(aqn), INativeHandleContract)
            Dim fe As FrameworkElement = CType(FrameworkElementAdapters.ContractToViewAdapter(inhc), FrameworkElement)
            ' Add FrameworkElement (which displays the UI provided by the add-in) as
            ' content of the view (a UserControl)
            Me.Content = fe
        End Sub
    End Class
End Namespace
Som du ser hämtar adaptern på värdsidan INativeHandleContract genom att anropa tilläggsadapterns QueryContract metod (det här är den punkt där INativeHandleContract korsar isoleringsgränsen).
Adaptern på värdsidan konverterar INativeHandleContract sedan till en FrameworkElement genom att anropa ContractToViewAdapter. Slutligen FrameworkElement anges som innehållet i värdvyn.
Implementeringen av Add-In
Med adapter för tilläggssidan och tilläggsvyn på plats kan tillägget implementeras genom att utgå från tilläggsvyn, enligt följande kod.
using System.AddIn;
using System.Windows;
using AddInViews;
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");
        }
    }
}
Imports System.AddIn
Imports System.Windows
Imports AddInViews
Namespace WPFAddIn1
    ''' <summary>
    ''' Implements the add-in by deriving from WPFAddInView
    ''' </summary>
    <AddIn("WPF Add-In 1")>
    Partial Public Class AddInUI
        Inherits WPFAddInView
        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
I det här exemplet kan du se en intressant fördel med den här modellen: tilläggsutvecklare behöver bara implementera tillägget (eftersom det också är användargränssnittet) i stället för både en tilläggsklass och ett tilläggsgränssnitt.
Implementera värdprogrammet
När adaptern på värdsidan och värdvy har skapats kan värdprogrammet använda .NET Framework-tilläggsmodellen för att öppna pipelinen och hämta en värdvy av tillägget. De här stegen visas i följande kod.
// 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);
' 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(WPFAddInHostView), appPath)
Dim wpfAddInToken As AddInToken = addInTokens(0)
Me.wpfAddInHostView = wpfAddInToken.Activate(Of WPFAddInHostView)(AddInSecurityLevel.Internet)
' Display add-in UI
Me.addInUIHostGrid.Children.Add(Me.wpfAddInHostView)
Värdprogrammet använder typisk .NET Framework-tilläggsmodellkod för att aktivera tillägget, vilket implicit returnerar värdvyn till värdprogrammet. Värdprogrammet visar därefter värdvyn (som är en UserControl) från en Grid.
Koden för bearbetning av interaktioner med tilläggets användargränssnitt körs i tilläggets programdomän. Dessa interaktioner omfattar följande:
Visar MessageBox.
Den här aktiviteten är helt isolerad från värdprogrammet.
Se även
.NET Desktop feedback