Практическое руководство. Создание надстройки, являющейся пользовательским интерфейсом
В этом примере показано, как создать надстройку, Windows Presentation Foundation (WPF), размещаемый в автономное приложение WPF.
Надстройка — это пользовательский Интерфейс, который является пользовательский элемент управления WPF. Содержимое пользовательского элемента управления составляет одна кнопка, при нажатии которой отображается окно сообщения. Автономное приложение WPF размещает пользовательского интерфейса надстройки как содержимое главного окна приложения.
Предварительные требования
В этом примере представлены расширения WPF модель надстроек платформы .NET Framework, реализовать этот сценарий и предполагается следующее:
Знание модели надстроек платформы .NET Framework, включая конвейер, надстройка и разработку основного приложения. Если вы не знакомы с этими понятиями, см. в разделе надстройки и расширения. Учебник, в котором демонстрируется реализация конвейера, надстройки и ведущего приложения, см. в разделе Пошаговое руководство: Создание расширяемого приложения.
Знание расширений WPF в .NET Framework модель. См. в разделе Общие сведения о надстройках WPF.
Пример
Создание надстройки, являющейся пользовательским Интерфейсом WPF требуется специальный код для каждого сегмента конвейера, надстройки и ведущего приложения.
Реализация сегмента конвейера контракта
Если надстройка является пользовательским Интерфейсом, контракт для надстройки должен реализовывать INativeHandleContract. В примере IWPFAddInContract
реализует INativeHandleContract, как показано в следующем коде.
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 {}
}
Реализация сегмента конвейера представления надстройки
Поскольку надстройка реализуется как подкласс FrameworkElement тип, представление надстройки также должно быть подклассом FrameworkElement. Ниже показано представление надстройки контракта, реализованное как WPFAddInView
класса.
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 { }
}
Здесь представление надстройки является производным от UserControl. Следовательно, пользовательского интерфейса надстройки также должен быть производным от UserControl.
Реализация сегмента конвейера адаптера надстройки
Контракт — INativeHandleContract, надстройка — FrameworkElement (как указано в сегменте конвейера представления надстройки). Таким образом FrameworkElement должны быть преобразованы в INativeHandleContract перед пересечением границы изоляции. Эту работу выполняет адаптер стороне надстройки, вызвав ViewToContractAdapter, как показано в следующем коде.
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 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();
}
}
}
В модели надстройки, где надстройка возвращает пользовательский Интерфейс (см. в разделе создание надстройки, возвращающей пользовательский Интерфейс), преобразовать адаптер надстройки FrameworkElement для INativeHandleContract путем вызова ViewToContractAdapter. ViewToContractAdapter также должен вызываться в этой модели, несмотря на то, что вам нужно реализовать метод, с которым следует записывать код для его вызова. Это делается путем переопределения QueryContract и реализация кода, который вызывает ViewToContractAdapter Если код, который вызывает QueryContract ожидает INativeHandleContract. В этом случае вызывающий объект будет адаптером приложения, который рассматривается в следующем подразделе.
Note
Необходимо также переопределить QueryContract в этой модели, чтобы разрешить переходы между ведущим приложением пользовательский Интерфейс и интерфейс пользователя надстройки. Дополнительные сведения см. в разделе «Add-In ограничения WPF» в Общие сведения о надстройках WPF.
Так как адаптер на стороне надстройки реализует интерфейс, который является производным от INativeHandleContract, необходимо также реализовать GetHandle, несмотря на то, что этот параметр игнорируется при QueryContract переопределяется.
Реализация сегмента конвейера представления в основном приложении
В этой модели ведущее приложение обычно ожидает, что хост-представление, быть FrameworkElement подкласс. Адаптер необходимо преобразовать INativeHandleContract для FrameworkElement после INativeHandleContract пересекает границу изоляции. Поскольку метод не вызывается ведущим приложением для получения FrameworkElement, представления главного приложения должно «вернуть» FrameworkElement , включая его. Следовательно, представление главного приложения должен быть производным от подкласс FrameworkElement , могут содержать другие UI, такие как UserControl. Ниже показано представление узла контракта, реализованное как WPFAddInHostView
класса.
Реализация сегмента конвейера адаптера приложения
Контракт — INativeHandleContract, а ведущее приложение ожидает UserControl (как указано представлением узла). Следовательно INativeHandleContract должны быть преобразованы в FrameworkElement после пересечения границы изоляции и перед заданием в качестве содержимого представления в ведущем приложении (который является производным от UserControl).
Эту работу выполняет адаптер приложения, как показано в следующем коде.
Как видите, адаптер получает INativeHandleContract путем вызова адаптер на стороне надстройки QueryContract метода (именно на этом этапе где INativeHandleContract пересекает границу изоляции).
Адаптер, затем преобразует INativeHandleContract для FrameworkElement путем вызова ContractToViewAdapter. Наконец FrameworkElement задается как содержимое представления главного приложения.
Реализация надстройки
При наличии адаптера надстройки и представления надстройки можно реализовать надстройку, производя ее от представления надстройки, как показано в следующем коде.
В этом примере можно увидеть одно любопытное преимущество данной модели: разработчикам должны реализовать только надстройку (поскольку это пользовательский интерфейс), а не класс надстройки и пользовательского интерфейса надстройки.
Реализация ведущего приложения
Адаптер на стороне узла и созданного представления узла, ведущее приложение может использовать .NET Framework в модели надстройки, чтобы открыть конвейер и получить серверное представление надстройки. Эти действия показаны в следующем коде.
Ведущее приложение использует типичный код модели надстроек платформы .NET Framework для активации надстройки, которая неявным образом возвращает представление главного приложения ведущим приложением. Ведущее приложение затем отображает представление главного приложения (который является UserControl) из Grid.
Код для обработки взаимодействия с помощью пользовательского интерфейса выполняется в домен приложения надстройки. Эти взаимодействия включают следующее.
Отображение MessageBox.
Это действие полностью изолировано от ведущего приложения.