다음을 통해 공유


방법: 사용자 지정 기능 커넥터 만들기

업데이트: 2007년 11월

다음 코드 예제에서는 사용자 지정 기능 커넥터를 구현하는 방법을 보여 줍니다. 자세한 내용은 연습: 디자인 타임 표시기 만들기를 참조하십시오.

예제

다음 코드 예제에서는 FeatureConnector<FeatureProviderType> 클래스에서 파생하여 DiagnosticsMenuProvider라는 사용자 지정 기능 공급자와 IDiagnosticsService라는 사용자 지정 서비스를 연결하는 방법을 보여 줍니다.

Imports System
Imports System.Windows

' The DemoButton control provides a button that
' has custom design-time behavior. 
Public Class DemoButton
    Inherits System.Windows.Controls.Button
End Class
using System;
using System.Windows;

namespace DemoControlLibrary
{
    // The DemoButton control provides a button that
    // has custom design-time behavior. 
    public class DemoButton : System.Windows.Controls.Button 
    {

    }
}
Imports System
Imports Microsoft.Windows.Design.Features
Imports Microsoft.Windows.Design.Interaction

' The DiagnosticsMenuProvider class adds a context menu item
' that displays a dialog box listing the currently running and 
' pending feature connectors. 
<FeatureConnector(GetType(DiagnosticsFeatureConnector))>  _
Public Class DiagnosticsMenuProvider
    Inherits PrimarySelectionContextMenuProvider

    Public Sub New() 
        Dim action As New MenuAction("Feature Diagnostics...")

        AddHandler action.Execute, AddressOf action_Execute 

        Items.Add(action)    
    End Sub

    Sub action_Execute(ByVal sender As Object, ByVal e As MenuActionEventArgs) 
        Dim service As IDiagnosticsService = e.Context.Services.GetRequiredService(Of IDiagnosticsService)()

        service.ShowWindow()

    End Sub

End Class

' The IDiagnosticsService specifies a simple interface for showing
' a FeatureManagerDiagnostics window.
Interface IDiagnosticsService
    Sub ShowWindow() 
End Interface

' The DiagnosticsFeatureConnector publishes the IDiagnosticsService. 
Class DiagnosticsFeatureConnector
    Inherits FeatureConnector(Of DiagnosticsMenuProvider)
    Implements IDiagnosticsService

    Dim fmdWindow As FeatureManagerDiagnostics

    Public Sub New(ByVal manager As FeatureManager) 
        MyBase.New(manager)

        Context.Services.Publish(Of IDiagnosticsService)(Me)

    End Sub

    ' The showWindow method creates a FeatureManagerDiagnostics
    ' window and shows it.
    Public Sub ShowWindow() Implements IDiagnosticsService.ShowWindow

        If fmdWindow IsNot Nothing Then

            ' Show the FeatureManagerDiagnostics window.
            fmdWindow.Show()

            ' Activate the 
            fmdWindow.Activate()

        Else

            fmdWindow = New FeatureManagerDiagnostics()
            fmdWindow.Initialize(Manager)
            AddHandler fmdWindow.Closed, AddressOf fmdWindow_Closed
            fmdWindow.Show()

        End If

    End Sub

    Sub fmdWindow_Closed(ByVal sender As Object, ByVal e As EventArgs)

        fmdWindow = Nothing

    End Sub

End Class
using System;
using Microsoft.Windows.Design.Features;
using Microsoft.Windows.Design.Interaction;

namespace DemoControlLibrary.VisualStudio.Design
{
    // The DiagnosticsMenuProvider class adds a context menu item
    // that displays a dialog box listing the currently running and 
    // pending feature connectors. 
    [FeatureConnector(typeof(DiagnosticsFeatureConnector))]
    public class DiagnosticsMenuProvider : PrimarySelectionContextMenuProvider 
    {
        public DiagnosticsMenuProvider() 
        {
            MenuAction action = new MenuAction("Feature Diagnostics...");

            action.Execute += new EventHandler<MenuActionEventArgs>(action_Execute); 

            Items.Add(action);
        }

        void action_Execute(object sender, MenuActionEventArgs e)
        {
            IDiagnosticsService service = 
                e.Context.Services.GetRequiredService<IDiagnosticsService>();

            service.ShowWindow();
        }
    }

    // The IDiagnosticsService specifies a simple interface for showing
    // a FeatureManagerDiagnostics window.
    interface IDiagnosticsService 
    {
        void ShowWindow();
    }

    // The DiagnosticsFeatureConnector publishes the IDiagnosticsService. 
    class DiagnosticsFeatureConnector : FeatureConnector<DiagnosticsMenuProvider>,
        IDiagnosticsService 
    {
        FeatureManagerDiagnostics fmdWindow;

        public DiagnosticsFeatureConnector(FeatureManager manager)
            : base(manager) 
        {
            Context.Services.Publish<IDiagnosticsService>(this);
        }

        #region IDiagnosticsService Members

        // The showWindow method creates a FeatureManagerDiagnostics
        // window and shows it.
        public void ShowWindow() 
        {
            if (fmdWindow != null) 
            {
                fmdWindow.Show();
                fmdWindow.Activate();
            }
            else 
            {
                fmdWindow = new FeatureManagerDiagnostics();
                fmdWindow.Initialize(Manager);
                fmdWindow.Closed += new EventHandler(fmdWindow_Closed); 
                fmdWindow.Show();
            }
        }

        void fmdWindow_Closed(object sender, EventArgs e)
        {
            fmdWindow = null; 
        }

        #endregion
    }
}
Imports System
Imports System.Collections.Generic
Imports System.Text
Imports System.Windows
Imports System.Windows.Controls
Imports System.Windows.Data
Imports System.Windows.Documents
Imports System.Windows.Input
Imports System.Windows.Media
Imports System.Windows.Media.Imaging
Imports System.Windows.Shapes

Imports Microsoft.Windows.Design.Features

' The FeatureManagerDiagnostics class implements a window
' that displays the running and pending feature connectors.
Partial Public Class FeatureManagerDiagnostics
    Inherits Window

    Private featManager As FeatureManager

    Public Sub New()
        InitializeComponent()

    End Sub

    Public Sub Initialize(ByVal manager As FeatureManager)
        featManager = manager
        Bind()
    End Sub

    Private Sub OnRefreshClick(ByVal sender As Object, ByVal e As RoutedEventArgs)
        Bind()
    End Sub

    ' Binds the activatedFeatures and pendingFeatures controls
    ' the FeatureManager's RunningConnectors and PendingConnectors\
    ' properties.
    Private Sub Bind()
        activatedFeatures.Items.Clear()
        pendingFeatures.Items.Clear()

        Dim info As FeatureConnectorInformation
        For Each info In featManager.RunningConnectors
            activatedFeatures.Items.Add(info)
        Next info

        For Each info In featManager.PendingConnectors
            pendingFeatures.Items.Add(info)
        Next info

    End Sub

End Class
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;

using Microsoft.Windows.Design.Features;

namespace DemoControlLibrary.VisualStudio.Design
{
    // The FeatureManagerDiagnostics class implements a window
    // that displays the running and pending feature connectors.
    public partial class FeatureManagerDiagnostics : Window 
    {
        private FeatureManager featManager;

        public FeatureManagerDiagnostics() 
        {
            InitializeComponent();
        }

        public void Initialize(FeatureManager manager) 
        {
            featManager = manager;
            Bind();
        }

        private void OnRefreshClick(object sender, RoutedEventArgs e) 
        {
            Bind();
        }

        // Binds the activatedFeatures and pendingFeatures controls
        // the FeatureManager's RunningConnectors and PendingConnectors\
        // properties.
        private void Bind() 
        {
            activatedFeatures.Items.Clear();
            pendingFeatures.Items.Clear();

            foreach (FeatureConnectorInformation info in 
                featManager.RunningConnectors) 
            {
                activatedFeatures.Items.Add(info);
            }

            foreach (FeatureConnectorInformation info in 
                featManager.PendingConnectors) 
            {
                pendingFeatures.Items.Add(info);
            }
        }
    }
}
<Window 
  xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:l="clr-namespace:DemoControlLibrary.VisualStudio.Design"
  x:Class="FeatureManagerDiagnostics"
  Title="Feature Diagnostics" WindowStartupLocation="CenterOwner" SizeToContent="Manual" Height="316" Width="448" >

  <Window.Resources>
    <Style x:Key="HeaderStyle" TargetType="HeaderedItemsControl">

      <Setter Property="Template">
        <Setter.Value>
          <ControlTemplate TargetType="HeaderedItemsControl">
            <StackPanel>
              <Border Padding="5" Background="#FFDDDDDD">
                <CheckBox IsChecked="True" FontWeight="Bold" Name="Expander" Content="{TemplateBinding Header}"/>
              </Border>
              <Border Padding="5" Name="ItemsHost">
                <ItemsPresenter/>
              </Border>
            </StackPanel>

            <ControlTemplate.Triggers>
              <Trigger SourceName="Expander" Property="ToggleButton.IsChecked" Value="true">
                <Setter TargetName="ItemsHost" Property="Visibility" Value="Visible" />
              </Trigger>
              <Trigger SourceName="Expander" Property="ToggleButton.IsChecked" Value="false">
                <Setter TargetName="ItemsHost" Property="Visibility" Value="Collapsed" />
              </Trigger>
            </ControlTemplate.Triggers>
          </ControlTemplate>
        </Setter.Value>
      </Setter>
    </Style>

    <DataTemplate x:Key="FeatureInfo" DataType="l:FeatureConnectorInformation">
      <StackPanel>
        <Border BorderBrush="{x:Static SystemColors.ActiveCaptionBrush}" BorderThickness="0,0,0,1">
          <TextBlock FontWeight="Bold" Text="{Binding Path=FeatureConnectorType}" />
        </Border>
        <Border Padding="15,0,0,5" TextElement.FontSize = "10">
          <StackPanel>
            <TextBlock FontWeight="Bold" Text="Required Services" />
            <Border Padding="10,0,0,5">
              <ItemsControl ItemsSource="{Binding Path=RequiredServices}" />
            </Border>
            <TextBlock FontWeight="Bold" Text="Required Context Items" />
            <Border Padding="10,0,0,5">
              <ItemsControl ItemsSource="{Binding Path=RequiredItems}" />
            </Border>
          </StackPanel>
        </Border>
      </StackPanel>
    </DataTemplate>

    <DataTemplate x:Key="PendingFeatureInfo" DataType="l:FeatureConnectorInformation">
      <StackPanel>
        <Border BorderBrush="{x:Static SystemColors.ActiveCaptionBrush}" BorderThickness="0,0,0,1">
          <TextBlock FontWeight="Bold" Text="{Binding Path=FeatureConnectorType}" />
        </Border>
        <Border Padding="15,0,0,5" TextElement.FontSize = "10">
          <StackPanel>
            <TextBlock FontWeight="Bold" Text="Missing Services" />
            <Border Padding="10,0,0,5">
              <ItemsControl ItemsSource="{Binding Path=PendingServices}" />
            </Border>
            <TextBlock FontWeight="Bold" Text="Missing Context Items" />
            <Border Padding="10,0,0,5">
              <ItemsControl ItemsSource="{Binding Path=PendingItems}" />
            </Border>
          </StackPanel>
        </Border>
      </StackPanel>
    </DataTemplate>
  </Window.Resources> 

  <Grid>
    <ScrollViewer Margin="0,0,0,36" VerticalScrollBarVisibility="Auto">
      <StackPanel>
        <HeaderedItemsControl Name="pendingFeatures" Style="{StaticResource HeaderStyle}" Header="Pending Features" ItemTemplate="{StaticResource PendingFeatureInfo}" />
        <HeaderedItemsControl Name="activatedFeatures" Style="{StaticResource HeaderStyle}" Header="Activated Features" ItemTemplate="{StaticResource FeatureInfo}" />
      </StackPanel>
    </ScrollViewer>
    <Button Height="23" Margin="0,0,8,7" Click="OnRefreshClick" VerticalAlignment="Bottom" HorizontalAlignment="Right" Width="75">Refresh</Button>
  </Grid>

</Window>
<Window 
  xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
  xmlns:l="clr-namespace:DemoControlLibrary.VisualStudio.Design" 
  x:Class="DemoControlLibrary.VisualStudio.Design.FeatureManagerDiagnostics"
  Title="Feature Diagnostics" WindowStartupLocation="CenterOwner" SizeToContent="Manual" Height="316" Width="448" >

  <Window.Resources>
    <Style x:Key="HeaderStyle" TargetType="HeaderedItemsControl">

      <Setter Property="Template">
        <Setter.Value>
          <ControlTemplate TargetType="HeaderedItemsControl">
            <StackPanel>
              <Border Padding="5" Background="#FFDDDDDD">
                <CheckBox IsChecked="True" FontWeight="Bold" Name="Expander" Content="{TemplateBinding Header}"/>
              </Border>
              <Border Padding="5" Name="ItemsHost">
                <ItemsPresenter/>
              </Border>
            </StackPanel>

            <ControlTemplate.Triggers>
              <Trigger SourceName="Expander" Property="ToggleButton.IsChecked" Value="true">
                <Setter TargetName="ItemsHost" Property="Visibility" Value="Visible" />
              </Trigger>
              <Trigger SourceName="Expander" Property="ToggleButton.IsChecked" Value="false">
                <Setter TargetName="ItemsHost" Property="Visibility" Value="Collapsed" />
              </Trigger>
            </ControlTemplate.Triggers>
          </ControlTemplate>
        </Setter.Value>
      </Setter>
    </Style>

    <DataTemplate x:Key="FeatureInfo" DataType="l:FeatureConnectorInformation">
      <StackPanel>
        <Border BorderBrush="{x:Static SystemColors.ActiveCaptionBrush}" BorderThickness="0,0,0,1">
          <TextBlock FontWeight="Bold" Text="{Binding Path=FeatureConnectorType}" />
        </Border>
        <Border Padding="15,0,0,5" TextElement.FontSize = "10">
          <StackPanel>
            <TextBlock FontWeight="Bold" Text="Required Services" />
            <Border Padding="10,0,0,5">
              <ItemsControl ItemsSource="{Binding Path=RequiredServices}" />
            </Border>
            <TextBlock FontWeight="Bold" Text="Required Context Items" />
            <Border Padding="10,0,0,5">
              <ItemsControl ItemsSource="{Binding Path=RequiredItems}" />
            </Border>
          </StackPanel>
        </Border>
      </StackPanel>
    </DataTemplate>

    <DataTemplate x:Key="PendingFeatureInfo" DataType="l:FeatureConnectorInformation">
      <StackPanel>
        <Border BorderBrush="{x:Static SystemColors.ActiveCaptionBrush}" BorderThickness="0,0,0,1">
          <TextBlock FontWeight="Bold" Text="{Binding Path=FeatureConnectorType}" />
        </Border>
        <Border Padding="15,0,0,5" TextElement.FontSize = "10">
          <StackPanel>
            <TextBlock FontWeight="Bold" Text="Missing Services" />
            <Border Padding="10,0,0,5">
              <ItemsControl ItemsSource="{Binding Path=PendingServices}" />
            </Border>
            <TextBlock FontWeight="Bold" Text="Missing Context Items" />
            <Border Padding="10,0,0,5">
              <ItemsControl ItemsSource="{Binding Path=PendingItems}" />
            </Border>
          </StackPanel>
        </Border>
      </StackPanel>
    </DataTemplate>
  </Window.Resources>

  <Grid>
    <ScrollViewer Margin="0,0,0,36" VerticalScrollBarVisibility="Auto">
      <StackPanel>
        <HeaderedItemsControl Name="pendingFeatures" Style="{StaticResource HeaderStyle}" Header="Pending Features" ItemTemplate="{StaticResource PendingFeatureInfo}" />
        <HeaderedItemsControl Name="activatedFeatures" Style="{StaticResource HeaderStyle}" Header="Activated Features" ItemTemplate="{StaticResource FeatureInfo}" />
      </StackPanel>
    </ScrollViewer>
    <Button Height="23" Margin="0,0,8,7" Click="OnRefreshClick" VerticalAlignment="Bottom" HorizontalAlignment="Right" Width="75">Refresh</Button>
  </Grid>
</Window>
Imports System
Imports DemoControlLibrary

Imports Microsoft.Windows.Design.Metadata
Imports Microsoft.Windows.Design.Features

' Container for any general design-time metadata to initialize.
' Designers look for a type in the design-time assembly that 
' implements IRegisterMetadata. If found, designers instantiate 
' this class and call its Register() method automatically.
Friend Class Metadata
    Implements IRegisterMetadata

    Public Sub Register() Implements IRegisterMetadata.Register
        Dim builder As New AttributeTableBuilder()
        InitializeAttributes(builder)
        MetadataStore.AddAttributeTable(builder.CreateTable())
    End Sub

    Private Sub InitializeAttributes(ByVal builder As AttributeTableBuilder) 
        builder.AddCallback(GetType(DemoButton), AddressOf AddButtonAttributes)

    End Sub

    Private Sub AddButtonAttributes(ByVal builder As AttributeCallbackBuilder) 
        builder.AddCustomAttributes(New FeatureAttribute(GetType(DiagnosticsMenuProvider)))
    End Sub
End Class
' <//snippet101>
using System;
using DemoControlLibrary;

using Microsoft.Windows.Design.Metadata;
using Microsoft.Windows.Design.Features;

namespace DemoControlLibrary.VisualStudio.Design
{
    // Container for any general design-time metadata to initialize.
    // Designers look for a type in the design-time assembly that 
    // implements IRegisterMetadata. If found, designers instantiate 
    // this class and call its Register() method automatically.
    internal class Metadata : IRegisterMetadata 
    {
        public void Register() 
        {
            AttributeTableBuilder builder = new AttributeTableBuilder();
            InitializeAttributes(builder);
            MetadataStore.AddAttributeTable(builder.CreateTable());
        }

        private void InitializeAttributes(AttributeTableBuilder builder) 
        {
            builder.AddCallback(typeof(DemoButton), AddButtonAttributes);
        }

        private void AddButtonAttributes(AttributeCallbackBuilder builder)
        {
            builder.AddCustomAttributes(
                new FeatureAttribute(typeof(DiagnosticsMenuProvider))
            );
        }
    }
    // <//snippet101>
}
    <Window x:Class="Window1"
    xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:c="clr-namespace:DemoControlLibrary;assembly=DemoControlLibrary"
    Title="Window1" Height="300" Width="300">
    <Grid>
        <c:DemoButton />
    </Grid>
</Window>
<Window x:Class="DemoApplication.Window1"
    xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:c="clr-namespace:DemoControlLibrary;assembly=DemoControlLibrary" 
    Title="Window1" Height="300" Width="300">
    <Grid>
        <c:DemoButton />
    </Grid>
</Window>

DemoButton 클래스는 Button에서 파생되며 디자인 타임 메타데이터가 연결되는 클래스를 제공합니다.

DiagnosticsMenuProvider 클래스는 FeatureManagerDiagnostics 창을 표시하는 상황에 맞는 메뉴 항목을 추가합니다.

FeatureManagerDiagnostics 클래스는 실행 중인 기능 커넥터와 보류 중인 기능 커넥터를 표시하는 창을 구현합니다.

Metadata 클래스는 MetadataStore 클래스를 사용하여 DiagnosticsMenuProvider를 DemoButton에 연결합니다.

코드 컴파일

이전 예제 코드를 서로 다른 세 어셈블리로 컴파일합니다.

사용자 지정 컨트롤 컴파일

  1. Visual Studio에서 DemoControlLibrary라는 새 WPF 사용자 지정 컨트롤 라이브러리 프로젝트를 만듭니다.

  2. 모든 "CustomControl1"을 "DemoButton"으로 변경합니다.

  3. DemoButton 클래스의 기존 코드를 앞에 나오는 코드로 바꿉니다.

  4. 솔루션을 빌드합니다.

사용자 지정 기능 커넥터 컴파일

  1. DemoControlLibrary.VisualStudio.Design이라는 새 WPF 사용자 지정 컨트롤 라이브러리 프로젝트를 솔루션에 추가합니다.

  2. 프로젝트의 출력 경로를 "..\DemoControlLibrary\bin\Debug\"로 설정합니다.

  3. 프로젝트에서 Generic.xaml을 삭제합니다.

  4. 다음 어셈블리에 대한 참조를 추가합니다.

    • Microsoft.Windows.Design

    • Microsoft.Windows.Design.Extensibility

    • Microsoft.Windows.Design.Interaction

  5. DemoControlLibrary 프로젝트에 대한 참조를 추가합니다.

  6. 모든 "CustomControl1"을 "DiagnosticsMenuProvider"로 바꿉니다.

  7. DiagnosticsMenuProvider 클래스의 기존 코드를 앞에 나오는 코드로 바꿉니다.

  8. FeatureManagerDiagnostics라는 창(WPF) 항목을 프로젝트에 추가합니다.

  9. FeatureManagerDiagnostics 클래스의 기존 코드를 앞에 나오는 코드로 바꿉니다.

  10. FeatureManagerDiagnostics.xaml의 기존 XAML을 앞에 나오는 XAML로 바꿉니다.

  11. Metadata라는 클래스를 프로젝트에 추가합니다.

  12. Metadata 클래스의 기존 코드를 앞에 나오는 코드로 바꿉니다.

  13. 솔루션을 빌드합니다.

테스트 응용 프로그램 컴파일

  1. DemoApplication이라는 새 WPF 응용 프로그램 프로젝트를 솔루션에 추가합니다.

  2. DemoControlLibrary 프로젝트에 대한 참조를 추가합니다.

  3. Window1.xaml의 기존 XAML을 위에 나열된 XAML로 바꿉니다.

  4. 디자인 뷰에서 단추를 마우스 오른쪽 단추로 클릭하고 Feature Diagnostics을 선택합니다.

    Feature Diagnostics 창이 나타나고 보류 중인 기능 커넥터 및 활성화된 기능 커넥터가 표시됩니다.

참고 항목

작업

연습: 디자인 타임 표시기 만들기

개념

기능 공급자 및 기능 커넥터

참조

FeatureManager

FeatureProvider

FeatureConnector<FeatureProviderType>

FeatureConnectorAttribute

MetadataStore

기타 리소스

WPF Designer 확장성