Sdílet prostřednictvím


Exemplarische Vorgehensweise: Implementieren der direkten Bearbeitung

Aktualisiert: November 2007

In dieser exemplarischen Vorgehensweise wird veranschaulicht, wie Sie die direkte Bearbeitung für ein benutzerdefiniertes WPF (Windows Presentation Foundation)-Steuerelement implementieren. Mit diesem Entwurfszeitfeature im Windows Presentation Foundation (WPF)-Designer für Visual Studio können Sie den Wert der Content-Eigenschaft für ein benutzerdefiniertes Schaltflächen-Steuerelement festlegen. Bei dem Steuerelement in dieser exemplarischen Vorgehensweise handelt es sich um eine einfache Schaltfläche, und bei dem Adorner um ein Textfeld, mit dem Sie den Inhalt der Schaltfläche ändern können.

Im Verlauf dieser exemplarischen Vorgehensweise führen Sie folgende Aufgaben aus:

  • Erstellen eines benutzerdefinierten WPF-Steuerelementbibliothek-Projekts

  • Erstellen einer separaten Assembly für Entwurfszeitmetadaten

  • Implementieren des Adorneranbieters für die direkte Bearbeitung

  • Testen des Steuerelements zur Entwurfszeit

Nach Abschluss dieser Aufgaben wissen Sie, wie Sie einen Adorneranbieter für ein benutzerdefiniertes Steuerelement erstellen.

Bb907383.alert_note(de-de,VS.90).gifHinweis:

Je nach den aktiven Einstellungen bzw. der Version unterscheiden sich die Dialogfelder und Menübefehle auf Ihrem Bildschirm unter Umständen von den in der Hilfe beschriebenen. Klicken Sie zum Ändern der Einstellungen im Menü Extras auf Einstellungen importieren und exportieren. Weitere Informationen finden Sie unter Visual Studio-Einstellungen.

Vorbereitungsmaßnahmen

Zum Durchführen dieser exemplarischen Vorgehensweise benötigen Sie die folgenden Komponenten:

  • Visual Studio 2008.

Erstellen des benutzerdefinierten Steuerelements

Zuerst wird das Projekt für das benutzerdefinierte Steuerelement erstellt. Bei dem Steuerelement handelt es sich um eine einfache Schaltfläche mit wenig Entwurfszeitcode, für die eine GetIsInDesignMode-Methode zum Implementieren eines Entwurfszeitverhaltens verwendet wird.

So erstellen Sie das benutzerdefinierte Steuerelement

  1. Erstellen Sie ein neues benutzerdefiniertes WPF-Steuerelementbibliothek-Projekt in Visual C# mit dem Namen CustomControlLibrary.

    Der Code für CustomControl1 wird im Code-Editor geöffnet.

  2. Ändern Sie im Projektmappen-Explorer den Namen der Codedatei in DemoControl.cs. Wenn eine Meldung mit der Frage angezeigt wird, ob Sie eine Umbenennung für alle Verweise in diesem Projekt vornehmen möchten, klicken Sie auf Ja.

  3. Erweitern Sie im Projektmappen-Explorer den Ordner Designs.

  4. Doppelklicken Sie auf Generic.xaml.

    Generic.xaml wird im WPF-Designer geöffnet.

  5. Ersetzen Sie in der XAML-Ansicht alle Vorkommen von "CustomControl1" durch "DemoControl".

  6. Öffnen Sie DemoControl.cs im Code-Editor.

  7. Ersetzen Sie den automatisch generierten Code durch den folgenden Code. Das benutzerdefinierte DemoControl-Steuerelement erbt vom Button.

    using System;
    using System.Windows;
    using System.Windows.Controls;
    
    namespace CustomControlLibrary
    {
        public class DemoControl : Button
        {   
        }
    }
    
  8. Legen Sie den Ausgabepfad des Projekts auf "bin\" fest.

  9. Erstellen Sie die Projektmappe.

Erstellen der Entwurfszeit-Metadatenassembly

Entwurfszeitcode wird in speziellen Metadatenassemblys bereitgestellt. Weitere Informationen finden Sie unter Gewusst wie: Verwenden des Metadatenspeichers. Bei dieser exemplarischen Vorgehensweise wird der benutzerdefinierte Adorner nur von Visual Studio unterstützt und in einer Assembly mit dem Namen CustomControlLibrary.VisualStudio.Design bereitgestellt.

So erstellen Sie die Entwurfszeit-Metadatenassembly

  1. Fügen Sie der Projektmappe ein neues Klassenbibliothek-Projekt in Visual C# mit dem Namen CustomControlLibrary.VisualStudio.Design hinzu.

  2. Legen Sie den Ausgabepfad des Projekts auf "..\CustomControlLibrary\bin\" fest. Dadurch wird die Assembly des Steuerelements im selben Ordner wie die Metadatenassembly gespeichert, wodurch Designern die Metadatensuche ermöglicht wird.

  3. Fügen Sie Verweise auf die folgenden WPF-Assemblys hinzu.

    • PresentationCore

    • PresentationFramework

    • WindowsBase

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

    • Microsoft.Windows.Design

    • Microsoft.Windows.Design.Extensibility

    • Microsoft.Windows.Design.Interaction

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

  6. Ändern Sie im Projektmappen-Explorer den Namen der Class1-Codedatei in Metadata.cs.

  7. Ersetzen Sie den automatisch generierten Code durch den folgenden Code. Durch diesen Code wird eine AttributeTable erstellt, mit der die benutzerdefinierte Entwurfszeitimplementierung an die DemoControl-Klasse angefügt wird.

    using System;
    using Microsoft.Windows.Design.Features;
    using Microsoft.Windows.Design.Metadata;
    
    namespace CustomControlLibrary.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
        {
            // Called by the designer to register any design-time metadata.
            public void Register()
            {
                AttributeTableBuilder builder = new AttributeTableBuilder();
    
                // Add the adorner provider to the design-time metadata.
                builder.AddCustomAttributes(
                    typeof(DemoControl),
                    new FeatureAttribute(typeof(InplaceButtonAdorners)));
    
                MetadataStore.AddAttributeTable(builder.CreateTable());
    
            }
        }
    }
    
  8. Speichern Sie die Projektmappe.

Implementieren des Adorneranbieters

Der Adorneranbieter wird in einem Typ mit dem Namen InplaceButtonAdorners implementiert. Dieser Adorneranbieter ermöglicht es dem Benutzer, die Content-Eigenschaft des Steuerelements zur Entwurfszeit festzulegen.

So implementieren Sie den Adorneranbieter

  1. Fügen Sie dem CustomControlLibrary.VisualStudio.Design-Projekt eine neue Klasse mit dem Namen InplaceButtonAdorners hinzu.

  2. Ersetzen Sie im Code-Editor für InplaceButtonAdorners den automatisch generierten Code durch den folgenden Code. Mit diesem Code wird ein PrimarySelectionAdornerProvider implementiert, der einen auf einem TextBox-Steuerelement basierenden Adorner bereitstellt.

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Shapes;
    using Microsoft.Windows.Design.Interaction;
    using System.Windows.Data;
    using System.Windows.Input;
    using System.ComponentModel;
    using Microsoft.Windows.Design.Model;
    
    namespace CustomControlLibrary.VisualStudio.Design
    {
        // The InplaceButtonAdorners class provides two adorners:  
        // an activate glyph that, when clicked, activates in-place 
        // editing, and an in-place edit control, which is a text box.
        internal class InplaceButtonAdorners : PrimarySelectionAdornerProvider
        {
            private Rectangle activateGlyph;
            private TextBox editGlyph;
            private AdornerPanel adornersPanel;
    
            public InplaceButtonAdorners()
            {
                adornersPanel = new AdornerPanel();
                adornersPanel.IsContentFocusable = true;
                adornersPanel.Children.Add(ActivateGlyph);
    
                Adorners.Add(adornersPanel);
            }
    
            private UIElement ActivateGlyph
            {
                get
                {
                    if (activateGlyph == null)
                    {
                        // The following code specifies the shape of the activate 
                        // glyph. This can also be implemented by using a XAML template.
                        Rectangle glyph = new Rectangle();
                        glyph.Fill = AdornerColors.HandleFillBrush;
                        glyph.Stroke = AdornerColors.HandleBorderBrush;
                        glyph.RadiusX = glyph.RadiusY = 2;
                        glyph.Width = 10;
                        glyph.Height = 5;
                        glyph.Cursor = Cursors.Hand;
    
                        ToolTipService.SetToolTip(
                            glyph, 
                            "Click to edit the text of the button.  " + 
                            "Enter to commit, ESC to cancel.");
    
                        // Position the glyph to the upper left of the DemoControl, 
                        // and slightly inside.
                        AdornerPlacementCollection placement = new AdornerPlacementCollection();
                        placement.PositionRelativeToContentHeight(0, 10);
                        placement.PositionRelativeToContentWidth(0, 5);
                        placement.SizeRelativeToAdornerDesiredHeight(1, 0);
                        placement.SizeRelativeToAdornerDesiredWidth(1, 0);
    
                        AdornerPanel.SetPlacements(glyph, placement);
    
                        // Add interaction to the glyph.  A click starts in-place editing.
                        ToolCommand command = new ToolCommand("ActivateEdit");
                        Task task = new Task();
                        task.InputBindings.Add(new InputBinding(command, new ToolGesture(ToolAction.Click)));
                        task.ToolCommandBindings.Add(new ToolCommandBinding(command, OnActivateEdit));
                        AdornerProperties.SetTask(glyph, task);
                        activateGlyph = glyph;
                    }
    
                    return activateGlyph;
                }
            }
            // When in-place editing is activated, a text box is placed 
            // over the control and focus is set to its input task. 
            // Its task commits itself when the user presses enter or clicks 
            // outside the control.
            private void OnActivateEdit(object sender, ExecutedToolEventArgs args)
            {
                adornersPanel.Children.Remove(ActivateGlyph);
                adornersPanel.Children.Add(EditGlyph);
    
                // Once added, the databindings activate. 
                // All the text can now be selected.
                EditGlyph.SelectAll();
                EditGlyph.Focus();
    
                GestureData data = GestureData.FromEventArgs(args);
                Task task = AdornerProperties.GetTask(EditGlyph);
                task.Description = "Edit text";
                task.BeginFocus(data);
            }
    
            // The EditGlyph utility property creates a TextBox to use as 
            // the in-place editing control. This property centers the TextBox
            // inside the target control and sets up data bindings between 
            // the TextBox and the target control.
            private TextBox EditGlyph
            {
                get
                {
                    if (editGlyph == null)
                    {
                        TextBox glyph = new TextBox();
                        glyph.BorderThickness = new Thickness(0);
                        glyph.Margin = new Thickness(4);
    
                        AdornerPlacementCollection placement = new AdornerPlacementCollection();
                        placement.PositionRelativeToContentWidth(0, 0);
                        placement.PositionRelativeToContentHeight(0, 0);
                        placement.SizeRelativeToContentHeight(1, 0);
                        placement.SizeRelativeToContentWidth(1, 0);
    
                        AdornerPanel.SetPlacements(glyph, placement);
    
                        // Data bind the glyph's vertical and horizontal alignment
                        // to the target control's alignment properties.
                        Binding binding = new Binding();
                        binding.Source = glyph;
                        binding.Path = new PropertyPath(
                            "(0).(1)", 
                            AdornerProperties.ActualViewProperty, 
                            Button.HorizontalContentAlignmentProperty);
                        glyph.SetBinding(TextBox.HorizontalContentAlignmentProperty, binding);
    
                        binding = new Binding();
                        binding.Source = glyph;
                        binding.Path = new PropertyPath(
                            "(0).(1)", 
                            AdornerProperties.ActualViewProperty, 
                            Button.VerticalContentAlignmentProperty);
                        glyph.SetBinding(TextBox.VerticalContentAlignmentProperty, binding);
    
                        // Make the glyph's background match the control's background. 
                        binding = new Binding();
                        binding.Source = glyph;
                        binding.Path = new PropertyPath(
                            "(0).(1)", 
                            AdornerProperties.ActualViewProperty, 
                            Button.BackgroundProperty);
                        glyph.SetBinding(TextBox.BackgroundProperty, binding);
    
                        // Two-way data bind the text box's text property to content.
                        binding = new Binding();
                        binding.Source = glyph;
                        binding.Path = new PropertyPath("(0).(1)[Content].(2)",
                          AdornerProperties.ActualModelProperty,
                          TypeDescriptor.GetProperties(
                              typeof(ModelItem))["Properties"],
                              TypeDescriptor.GetProperties(
                                  typeof(ModelProperty))["ComputedValue"]);
                        binding.Mode = BindingMode.TwoWay;
                        binding.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
                        binding.Converter = new ContentConverter();
                        glyph.SetBinding(TextBox.TextProperty, binding);
    
                        // Create a task that describes the UI interaction.
                        ToolCommand commitCommand = new ToolCommand("Commit Edit");
                        Task task = new Task();
                        task.InputBindings.Add(
                            new InputBinding(
                                commitCommand, 
                                new KeyGesture(Key.Enter)));
    
                        task.ToolCommandBindings.Add(
                            new ToolCommandBinding(commitCommand, delegate
                        {
                            task.Complete();
                        }));
    
                        task.FocusDeactivated += delegate
                        {
                            adornersPanel.Children.Remove(EditGlyph);
                            adornersPanel.Children.Add(ActivateGlyph);
                        };
    
                        AdornerProperties.SetTask(glyph, task);
    
                        editGlyph = glyph;
                    }
    
                    return editGlyph;
                }
            }
    
            // The ContentConverter class ensures that only strings
            // are assigned to the Text property of EditGlyph.
            private class ContentConverter : IValueConverter
            {
                public object Convert(
                    object value, 
                    Type targetType, 
                    object parameter, 
                    System.Globalization.CultureInfo culture)
                {
                    if (value is string)
                    {
                        return value;
                    }
    
                    return string.Empty;
                }
    
                public object ConvertBack(
                    object value, 
                    Type targetType, 
                    object parameter, 
                    System.Globalization.CultureInfo culture)
                {
                    return value;
                }
            }
        }
    }
    
  3. Erstellen Sie die Projektmappe.

Testen der Entwurfszeitimplementierung

Sie können die DemoControl-Klasse auf dieselbe Art wie jedes andere WPF-Steuerelement verwenden. Der WPF-Designer behandelt die Erstellung aller Entwurfszeitobjekte.

So testen Sie die Entwurfszeitimplementierung

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

    In WPF-Designer wird die Datei Window1.xaml geöffnet.

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

  3. Ersetzen Sie in der XAML-Ansicht den automatisch generierten XAML-Code durch den folgenden XAML-Code. Mit diesem XAML-Code werden ein Verweis auf den CustomControlLibrary-Namespace sowie das benutzerdefinierte DemoControl-Steuerelement hinzugefügt. Wenn das Steuerelement nicht angezeigt wird, müssen Sie möglicherweise auf die Informationsleiste am oberen Rand des Designers klicken, um die Ansicht zu aktualisieren.

    <Window x:Class="DemoApplication.Window1"
        xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:ccl="clr-namespace:CustomControlLibrary;assembly=CustomControlLibrary"
        Title="Window1" Height="300" Width="300">
        <Grid>
            <ccl:DemoControl></ccl:DemoControl>
        </Grid>
    </Window>
    
  4. Generieren Sie die Projektmappe neu.

  5. Klicken Sie in der Entwurfsansicht auf das DemoControl-Steuerelement, um es auszuwählen.

    Ein kleines Rectangle-Symbol wird an der linken oberen Ecke des DemoControl-Steuerelements angezeigt.

  6. Klicken Sie auf das Rectangle-Symbol, um die direkte Bearbeitung zu aktivieren.

    In einem Textfeld wird der Content von DemoControl angezeigt. Da der Inhalt derzeit leer ist, wird in der Mitte der Schaltfläche nur ein Cursor angezeigt.

  7. Geben Sie einen neuen Wert für den Textinhalt ein, und drücken Sie dann die EINGABETASTE.

    In der XAML-Ansicht wird die Content-Eigenschaft auf den Textwert festgelegt, den Sie in der Entwurfsansicht eingegeben haben.

  8. Legen Sie das DemoApplication-Projekt als Startprojekt fest, und führen Sie die Projektmappe aus.

    Zur Laufzeit hat die Schaltfläche den Textwert, den Sie mit dem Adorner festlegen.

Nächste Schritte

Sie können benutzerdefinierten Steuerelementen weitere benutzerdefinierte Entwurfszeitfeatures hinzufügen.

Siehe auch

Weitere Ressourcen

Erstellen von benutzerdefinierten Editoren

WPF-Designer-Erweiterbarkeit