Freigeben über


Gewusst wie: Erstellen einer benutzerdefinierten Featureverbindung

Aktualisiert: November 2007

In den folgenden Codebeispielen wird gezeigt, wie eine benutzerdefinierte Featureverbindung implementiert wird. Weitere Informationen finden Sie unter Exemplarische Vorgehensweise: Erstellen eines Entwurfszeitadorners.

Beispiel

Im folgenden Codebeispiel wird veranschaulicht, wie von der FeatureConnector<FeatureProviderType>-Klasse abgeleitet wird, um einen benutzerdefinierten Featureanbieter mit dem Namen DiagnosticsMenuProvider einem benutzerdefinierten Dienst mit dem Namen IDiagnosticsService zuzuordnen.

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>

Die DemoButton-Klasse wird von Button abgeleitet und stellt eine Klasse bereit, an die Entwurfszeitmetadaten angefügt werden.

Die DiagnosticsMenuProvider-Klasse fügt ein Kontextmenüelement hinzu, das das Fenster FeatureManagerDiagnostics anzeigt.

Die FeatureManagerDiagnostics-Klasse implementiert ein Fenster, das die ausgeführten und anstehenden Featureverbindungen anzeigt.

Die Metadata-Klasse fügt mithilfe der MetadataStore-Klasse den DiagnosticsMenuProvider an das DemoButton-Element an.

Kompilieren des Codes

Kompilieren Sie den vorherigen Beispielcode in drei einzelne Assemblys.

Kompilieren des benutzerdefinierten Steuerelements

  1. Erstellen Sie in Visual Studio ein neues benutzerdefiniertes WPF-Steuerelementbibliothek-Projekt mit dem Namen DemoControlLibrary.

  2. Ersetzen Sie alle Vorkommen von "CustomControl1" durch "DemoButton".

  3. Ersetzen Sie den vorhandenen Code in der DemoButton-Klasse durch den zuvor aufgeführten Code.

  4. Erstellen Sie die Projektmappe.

Kompilieren der benutzerdefinierten Featureverbindung

  1. Fügen Sie der Projektmappe ein neues benutzerdefiniertes WPF-Steuerelementbibliothek-Projekt mit dem Namen DemoControlLibrary.VisualStudio.Design hinzu.

  2. Legen Sie den Ausgabepfad des Projekts auf "..\DemoControlLibrary\bin\Debug\" fest.

  3. Löschen Sie Generic.xaml aus dem Projekt.

  4. Fügen Sie Verweise auf die folgenden Assemblys hinzu.

    • Microsoft.Windows.Design

    • Microsoft.Windows.Design.Extensibility

    • Microsoft.Windows.Design.Interaction

  5. Fügen Sie einen Verweis auf das DemoControlLibrary-Projekt hinzu.

  6. Ersetzen Sie alle Vorkommen von "CustomControl1" durch "DiagnosticsMenuProvider".

  7. Ersetzen Sie den vorhandenen Code in der DiagnosticsMenuProvider-Klasse durch den zuvor aufgeführten Code.

  8. Fügen Sie dem Projekt ein Fensterelement (WPF) mit dem Namen FeatureManagerDiagnostics hinzu.

  9. Ersetzen Sie den vorhandenen Code in der FeatureManagerDiagnostics-Klasse durch den zuvor aufgeführten Code.

  10. Ersetzen Sie den in FeatureManagerDiagnostics.xaml vorhandenen XAML-Code durch den weiter oben aufgelisteten XAML-Code.

  11. Fügen Sie dem Projekt eine Klasse mit dem Namen Metadata hinzu.

  12. Ersetzen Sie den vorhandenen Code in der Metadata-Klasse durch den zuvor aufgeführten Code.

  13. Erstellen Sie die Projektmappe.

Kompilieren der Testanwendung

  1. Fügen Sie der Projektmappe ein neues WPF-Anwendungsprojekt mit dem Namen DemoApplication hinzu.

  2. Fügen Sie einen Verweis auf das DemoControlLibrary-Projekt hinzu.

  3. Ersetzen Sie den in Window1.xaml vorhandenen XAML-Code durch den weiter oben aufgelisteten XAML-Code.

  4. Klicken Sie in der Entwurfsansicht mit der rechten Maustaste auf die Schaltfläche, und wählen Sie dann Featurediagnose aus.

    Das Fenster Featurediagnose wird angezeigt, in dem anstehende und aktivierte Featureverbindungen angezeigt werden.

Siehe auch

Aufgaben

Exemplarische Vorgehensweise: Erstellen eines Entwurfszeitadorners

Konzepte

Featureanbieter und Featureverbindungen

Referenz

FeatureManager

FeatureProvider

FeatureConnector<FeatureProviderType>

FeatureConnectorAttribute

MetadataStore

Weitere Ressourcen

WPF-Designer-Erweiterbarkeit