방법: UI를 반환하는 추가 기능 만들기
이 예제에서는 호스트 WPF 독립 실행형 애플리케이션에 WPF(Windows Presentation Foundation)를 반환하는 추가 기능을 만드는 방법을 보여 줍니다.
추가 기능은 WPF 사용자 정의 컨트롤인 UI를 반환합니다. 이 사용자 정의 컨트롤의 콘텐츠는 클릭했을 때 메시지 상자를 표시하는 하나의 단추입니다. WPF 독립 실행형 애플리케이션에서는 이 추가 기능을 호스트하고 추가 기능에서 반환되는 사용자 정의 컨트롤을 주 애플리케이션 창 콘텐츠로 표시합니다.
필수 구성 요소
이 예제에서는 이러한 시나리오를 가능하게 하는 .NET Framework 추가 기능 모델에 대한 WPF 확장을 중점적으로 다루며 다음 사항을 가정합니다.
파이프라인, 추가 기능 및 호스트 개발을 포함한 .NET Framework 추가 기능 모델에 대해 알고 있습니다. 이러한 개념에 대해 잘 모를 경우에는 추가 기능 및 확장성을 참조하세요. 파이프라인, 추가 기능 및 호스트 애플리케이션의 구현을 설명하는 자습서를 보려면 연습: 확장 가능한 애플리케이션 만들기를 참조하세요.
.NET Framework 추가 기능 모델의 WPF 확장에 대한 지식이 있습니다(WPF 추가 기능 개요).
예제
WPF UI를 반환하는 추가 기능을 만들려면 파이프라인 세그먼트, 추가 기능 및 호스트 애플리케이션 각각에 대한 특정 코드가 필요합니다.
계약 파이프라인 세그먼트 구현
계약에서는 UI를 반환하고 반환 값이 INativeHandleContract 형식인 메서드를 정의해야 합니다. 다음 코드에서는 IWPFAddInContract
계약의 GetAddInUI
메서드를 통해 이를 보여 줍니다.
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
추가 기능 쪽 어댑터 파이프라인 세그먼트 구현
계약 메서드는 INativeHandleContract를 반환하지만 추가 기능은 FrameworkElement를 반환합니다(추가 기능 보기에서 지정한 바와 같음). 따라서 격리 경계를 통과하기 전에 FrameworkElement를 INativeHandleContract로 변환해야 합니다. 이 작업은 다음 코드와 같이 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
호스트 측 어댑터 파이프라인 세그먼트 구현
계약 메서드는 INativeHandleContract를 반환하지만 호스트 애플리케이션은 FrameworkElement를 예상합니다(호스트 보기에서 지정한 바와 같음). 따라서 격리 경계를 통과한 후에 INativeHandleContract를 FrameworkElement로 변환해야 합니다. 이 작업은 다음 코드와 같이 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
추가 기능 구현
추가 기능 측 어댑터 및 추가 기능 보기가 생성되면 추가 기능(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)
참고 항목
.NET Desktop feedback