Condividi tramite


Procedura dettagliata: implementazione della modifica sul posto

Aggiornamento: novembre 2007

In questa procedura dettagliata viene illustrato come implementare modifiche sul posto per un controllo personalizzato WPF (Windows Presentation Foundation). Questa funzionalità Design-Time può essere utilizzata in Progettazione Windows Presentation Foundation (WPF) per Visual Studio per impostare il valore della proprietà Content su un controllo pulsante personalizzato. Per questa procedura dettagliata, il controllo è un semplice pulsante e lo strumento decorativo visuale è una casella di testo che consente di modificare il contenuto del pulsante.

In questa procedura dettagliata vengono eseguite le attività seguenti:

  • Creare un progetto di libreria di controlli personalizzati WPF.

  • Creare un assembly distinto per i metadati Design-Time.

  • Implementare il provider dello strumento decorativo visuale per la modifica sul posto.

  • Verificare il controllo in fase di progettazione.

Al termine, si sarà in grado di creare un provider di strumenti decorativi visuali per un controllo personalizzato.

Nota:

È possibile che le finestre di dialogo e i comandi di menu visualizzati siano diversi da quelli descritti nella Guida in linea, a seconda delle impostazioni attive o dell'edizione del programma. Per modificare le impostazioni, scegliere Importa/esporta impostazioni dal menu Strumenti. Per ulteriori informazioni, vedere Impostazioni di Visual Studio.

Prerequisiti

Per completare questa procedura dettagliata, è necessario disporre dei seguenti componenti:

  • Visual Studio 2008.

Creazione del controllo personalizzato

Il primo passaggio consiste nella creazione del progetto per il controllo personalizzato. Il controllo è un semplice pulsante con una piccola quantità di codice Design-Time che utilizza il metodo GetIsInDesignMode per implementare un comportamento in fase di progettazione.

Per creare il controllo personalizzato

  1. In Visual C# creare un nuovo progetto di libreria di controlli personalizzati WPF denominato CustomControlLibrary.

    Il codice per CustomControl1 verrà aperto nell'editor del codice.

  2. In Esplora soluzioni modificare il nome del file di codice in DemoControl.cs. Se viene visualizzata una finestra di messaggio in cui si richiede se eseguire un'operazione di ridenominazione per tutti i riferimenti del progetto, fare clic su Sì.

  3. In Esplora soluzioni espandere la cartella Themes.

  4. Fare doppio clic su Generic.xaml.

    Generic1.xaml verrà aperto in WPF Designer.

  5. In visualizzazione XAML sostituire tutte le occorrenze di "CustomControl1" con "DemoControl".

  6. Aprire il file DemoControl.cs nell'editor del codice.

  7. Sostituire il codice generato automaticamente con il codice seguente. Il controllo DemoControl personalizzato eredita da Button

    using System;
    using System.Windows;
    using System.Windows.Controls;
    
    namespace CustomControlLibrary
    {
        public class DemoControl : Button
        {   
        }
    }
    
  8. Impostare il percorso di output del progetto su "bin\".

  9. Compilare la soluzione.

Creazione dell'assembly di metadati Design-Time

Il codice Design-Time viene distribuito in speciali assembly di metadati. Per ulteriori informazioni, vedere Procedura: utilizzare l'archivio di metadati. Per questa procedura dettagliata, lo strumento decorativo visuale personalizzato è supportato solo da Visual Studio ed è distribuito in un assembly denominato CustomControlLibrary.VisualStudio.Design.

Per creare l'assembly di metadati Design-Time

  1. In Visual C# aggiungere alla soluzione un nuovo progetto di libreria di classi denominato CustomControlLibrary.VisualStudio.Design.

  2. Impostare il percorso di output del progetto su "..\CustomControlLibrary\bin\". In questo modo l'assembly del controllo e l'assembly dei metadati verranno mantenuti nella stessa cartella, consentendo l'individuazione di metadati per le finestre di progettazione.

  3. Aggiungere riferimenti agli assembly WPF riportati di seguito.

    • PresentationCore

    • PresentationFramework

    • WindowsBase

  4. Aggiungere riferimenti agli assembly WPF Designer riportati di seguito.

    • Microsoft.Windows.Design

    • Microsoft.Windows.Design.Extensibility

    • Microsoft.Windows.Design.Interaction

  5. Aggiungere un riferimento al progetto CustomControlLibrary.

  6. In Esplora soluzioni modificare il nome del file di codice Class1 in Metadata.cs.

  7. Sostituire il codice generato automaticamente con il codice seguente. Con questo codice viene creato un oggetto AttributeTable che connette l'implementazione Design-Time personalizzata alla classe DemoControl.

    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. Salvare la soluzione.

Implementazione del provider di strumenti decorativi visuali

Il provider di strumenti decorativi visuali viene implementato in un tipo denominato InplaceButtonAdorners. Questo provider di strumenti decorativi visuali consente all'utente di impostare in fase di progettazione la proprietà Content del controllo.

Per implementare il provider di strumenti decorativi visuali

  1. Aggiungere una nuova classe denominata InplaceButtonAdorners al progetto CustomControlLibrary.VisualStudio.Design.

  2. Nell'editor del codice per InplaceButtonAdorners sostituire il codice generato automaticamente con il codice seguente. Questo codice implementa un PrimarySelectionAdornerProvider che fornisce uno strumento decorativo visuale basato su un controllo TextBox.

    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. Compilare la soluzione.

Test dell'implementazione Design-Time

È possibile utilizzare la classe DemoControl come qualsiasi altro controllo WPF. In WPF Designer viene gestita la creazione di tutti gli oggetti in fase di progettazione.

Per eseguire il test dell'implementazione in fase di progettazione

  1. In Visual C# aggiungere alla soluzione un nuovo progetto di applicazione WPF denominato DemoApplication.

    Window1.xaml verrà aperto in WPF Designer.

  2. Aggiungere un riferimento al progetto CustomControlLibrary.

  3. In visualizzazione XAML sostituire il codice XAML generato automaticamente con il seguente codice XAML. Con questo codice XAML viene aggiunto un riferimento allo spazio dei nomi CustomControlLibrary e viene aggiunto il controllo personalizzato DemoControl. Se il controllo non viene visualizzato, può essere necessario fare clic sulla barra informazioni nella parte superiore della finestra di progettazione per ricaricare la visualizzazione.

    <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. Ricompilare la soluzione.

  5. In visualizzazione Progettazione fare clic sul controllo DemoControl per selezionarlo.

    Nell'angolo superiore sinistro del controllo DemoControl viene visualizzato un piccolo glifo Rectangle.

  6. Fare clic sul glifo Rectangle per attivare la modifica sul posto.

    Viene visualizzata una casella di testo in cui viene mostrato l'oggetto Content dell'oggetto DemoControl. Dal momento che il contenuto è attualmente vuoto, viene visualizzato soltanto un cursore al centro del pulsante.

  7. Digitare un nuovo valore per il contenuto di testo, quindi premere il tasto INVIO.

    In visualizzazione XAML, la proprietà Content è impostata sul valore del testo digitato in visualizzazione Progettazione.

  8. Impostare il progetto DemoApplication come progetto di avvio ed eseguire la soluzione.

    In fase di esecuzione, il pulsante presenta il valore del testo impostato con lo strumento decorativo visuale.

Passaggi successivi

È possibile aggiungere altre funzionalità Design-Time ai controlli personalizzati.

Vedere anche

Altre risorse

Creazione di editor personalizzati

Estensibilità di Progettazione WPF