Files
docs-desktop/dotnet-desktop-guide/framework/wpf/app-development/how-to-create-an-add-in-that-is-a-ui.md
T
David CoulterandAndy De George 674b773578 Links: .NET Desktop - framework\wpf (#109)
* Links: .NET Desktop - framework\wpf

* Apply suggestions from code review

Co-authored-by: Andy De George <[email protected]>
2020-11-05 13:50:29 -08:00

11 KiB

title, ms.date, dev_langs, helpviewer_keywords, ms.assetid
title ms.date dev_langs helpviewer_keywords ms.assetid
How to: Create an Add-In That Is a UI 03/30/2017
csharp
vb
creating an add-in that is a UI [WPF]
add-ins [WPF], UI
creating UI add-ins [WPF]
UI add-ins [WPF], creating
implementing UI add-ins [WPF]
pipeline segments [WPF], creating add-ins
86375525-282b-4039-8352-8680051a10ea

How to: Create an Add-In That Is a UI

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

The add-in is a UI that is a WPF user control. The content of the user control is a single button that, when clicked, displays a message box. The WPF standalone application hosts the add-in UI as the content of the main application window.

Prerequisites

This example highlights the WPF extensions to the .NET Framework add-in model that enable this scenario, and assumes the following:

Example

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

Implementing the Contract Pipeline Segment

When an add-in is a UI, the contract for the add-in must implement xref:System.AddIn.Contract.INativeHandleContract. In the example, IWPFAddInContract implements xref:System.AddIn.Contract.INativeHandleContract, as shown in the following code.

[!code-csharpSimpleAddInIsAUISample#ContractCode] [!code-vbSimpleAddInIsAUISample#ContractCode]

Implementing the Add-In View Pipeline Segment

Because the add-in is implemented as a subclass of the xref:System.Windows.FrameworkElement type, the add-in view must also subclass xref:System.Windows.FrameworkElement. The following code shows the add-in view of the contract, implemented as the WPFAddInView class.

[!code-csharpSimpleAddInIsAUISample#AddInViewCode]
[!code-vbSimpleAddInIsAUISample#AddInViewCode]

Here, the add-in view is derived from xref:System.Windows.Controls.UserControl. Consequently, the add-in UI should also derive from xref:System.Windows.Controls.UserControl.

Implementing the Add-In-Side Adapter Pipeline Segment

While the contract is an xref:System.AddIn.Contract.INativeHandleContract, the add-in is a xref:System.Windows.FrameworkElement (as specified by the add-in view pipeline segment). Therefore, the xref:System.Windows.FrameworkElement must be converted to an xref:System.AddIn.Contract.INativeHandleContract before crossing the isolation boundary. This work is performed by the add-in-side adapter by calling xref:System.AddIn.Pipeline.FrameworkElementAdapters.ViewToContractAdapter%2A, as shown in the following code.

[!code-csharpSimpleAddInIsAUISample#AddInSideAdapterCode]
[!code-vbSimpleAddInIsAUISample#AddInSideAdapterCode]

In the add-in model where an add-in returns a UI (see Create an Add-In That Returns a UI), the add-in adapter converted the xref:System.Windows.FrameworkElement to an xref:System.AddIn.Contract.INativeHandleContract by calling xref:System.AddIn.Pipeline.FrameworkElementAdapters.ViewToContractAdapter%2A. xref:System.AddIn.Pipeline.FrameworkElementAdapters.ViewToContractAdapter%2A must also be called in this model, although you need to implement a method from which to write the code to call it. You do this by overriding xref:System.AddIn.Pipeline.ContractBase.QueryContract%2A and implementing the code that calls xref:System.AddIn.Pipeline.FrameworkElementAdapters.ViewToContractAdapter%2A if the code that is calling xref:System.AddIn.Pipeline.ContractBase.QueryContract%2A is expecting an xref:System.AddIn.Contract.INativeHandleContract. In this case, the caller will be the host-side adapter, which is covered in a subsequent subsection.

Note

You also need to override xref:System.AddIn.Pipeline.ContractBase.QueryContract%2A in this model to enable tabbing between host application UI and add-in UI. For more information, see "WPF Add-In Limitations" in WPF Add-Ins Overview.

Because the add-in-side adapter implements an interface that derives from xref:System.AddIn.Contract.INativeHandleContract, you also need to implement xref:System.AddIn.Contract.INativeHandleContract.GetHandle%2A, although this is ignored when xref:System.AddIn.Pipeline.ContractBase.QueryContract%2A is overridden.

Implementing the Host View Pipeline Segment

In this model, the host application typically expects the host view to be a xref:System.Windows.FrameworkElement subclass. The host-side adapter must convert the xref:System.AddIn.Contract.INativeHandleContract to a xref:System.Windows.FrameworkElement after the xref:System.AddIn.Contract.INativeHandleContract crosses the isolation boundary. Because a method isn't being called by the host application to get the xref:System.Windows.FrameworkElement, the host view must "return" the xref:System.Windows.FrameworkElement by containing it. Consequently, the host view must derive from a subclass of xref:System.Windows.FrameworkElement that can contain other UIs, such as xref:System.Windows.Controls.UserControl. The following code shows the host view of the contract, implemented as the WPFAddInHostView class.

[!code-csharpWPFAddInHostView class] [!code-vbWPFAddInHostView class]

Implementing the Host-Side Adapter Pipeline Segment

While the contract is an xref:System.AddIn.Contract.INativeHandleContract, the host application expects a xref:System.Windows.Controls.UserControl (as specified by the host view). Consequently, the xref:System.AddIn.Contract.INativeHandleContract must be converted to a xref:System.Windows.FrameworkElement after crossing the isolation boundary, before being set as content of the host view (which derives from xref:System.Windows.Controls.UserControl).

This work is performed by the host-side adapter, as shown in the following code.

[!code-csharpHost-side adapter] [!code-vbHost-side adapter]

As you can see, the host-side adapter acquires the xref:System.AddIn.Contract.INativeHandleContract by calling the add-in-side adapter's xref:System.AddIn.Pipeline.ContractBase.QueryContract%2A method (this is the point where the xref:System.AddIn.Contract.INativeHandleContract crosses the isolation boundary).

The host-side adapter then converts the xref:System.AddIn.Contract.INativeHandleContract to a xref:System.Windows.FrameworkElement by calling xref:System.AddIn.Pipeline.FrameworkElementAdapters.ContractToViewAdapter%2A. Finally, the xref:System.Windows.FrameworkElement is set as the content of the host view.

Implementing the Add-In

With the add-in-side adapter and add-in view in place, the add-in can be implemented by deriving from the add-in view, as shown in the following code.

[!code-csharpAdd-in implementation] [!code-vbAdd-in implementation]

From this example, you can see one interesting benefit of this model: add-in developers only need to implement the add-in (since it is the UI as well), rather than both an add-in class and an add-in UI.

Implementing the Host Application

With the host-side adapter and host view created, the host application can use the .NET Framework add-in model to open the pipeline and acquire a host view of the add-in. These steps are shown in the following code.

[!code-csharpAcquiring a host view of the add-in] [!code-vbAcquiring a host view of the add-in]

The host application uses typical .NET Framework add-in model code to activate the add-in, which implicitly returns the host view to the host application. The host application subsequently displays the host view (which is a xref:System.Windows.Controls.UserControl) from a xref:System.Windows.Controls.Grid.

The code for processing interactions with the add-in UI runs in the add-in's application domain. These interactions include the following:

This activity is completely isolated from the host application.

See also