Demonstra Passo a passo: Implementação de edição no local

Essa explicação passo a passo mostra como implementar edição in-loco para um controle personalizado Windows Presentation Foundation (WPF).Você pode usar esse recurso em tempo de design na caixa Windows Presentation Foundation (WPF) Designer for Visual Studio Para definir o valor da propriedade Content em um controle de botão personalizado.Para essa explicação passo a passo, o controle é um botão simples e o adorner é um caixa de texto que permite que você alterar o conteúdo do botão.

Nesta explicação passo a passo, você executa as seguintes tarefas:

  • Criar um projeto de biblioteca de controle personalizado WPF .

  • Criar um conjunto de módulos (assembly) separado de metadados em tempo de design.

  • Implemente o provedor de adorno para edição In-Place.

  • Testar o controle em tempo de design.

Quando você terminar, você saberá como criar um provedor de adorno para um controle personalizado.

Observação:

As caixas de diálogo e comandos de menu demonstradas podem ser diferentes daqueles descritas na Ajuda, dependendo das configurações ativas ou configurações de edição.Para alterar as configurações, escolher Importar e exportar configurações on the Ferramentas menu.Para obter mais informações, consulte Configurações do Visual Studio.

Pré-requisitos

Para completar este passo a passo, são necessários os seguintes componentes:

  • Visual Studio 2008.

Criando o Controle Personalizado

A primeira etapa é criar o projeto para o controle personalizado.O controle é um botão simples com pequena quantidade de código em tempo de design, que usa o método GetIsInDesignMode para implementar um comportamento de tempo de design.

Para criar o controle personalizado

  1. Crie um novo projeto da biblioteca de controle personalizado WPF no Visual C# denominado CustomControlLibrary .

    O código de CustomControl1 abre no Editor de Códigos.

  2. In O gerenciador de soluções, altere o nome do arquivo de código para DemoControl.cs.Se um caixa de mensagem aparecer que pergunta se você deseja executar uma renomeação para todas as referências no projeto atual, clique em Sim .

  3. Em Gerenciador de Soluções, expanda a pasta Temas.

  4. Clique duas vezes em Generic.xaml.

    Generic.xaml é aberto no WPF Designer.

  5. No modo de exibição XAML, substitua todas as ocorrências de "CustomControl1" com "ButtonWithDesignTime".

  6. Abra DemoControl.cs no Editor de Código.

  7. Substitua o código gerado automaticamente pelo código a seguir.O controle personalizado DemoControl herda de Button

    using System;
    using System.Windows;
    using System.Windows.Controls;
    
    namespace CustomControlLibrary
    {
        public class DemoControl : Button
        {   
        }
    }
    
  8. Defina o caminho de saída do projeto para "bin\".

  9. Crie a solução.

Criando o Conjunto de Módulos (Assembly) de Metadados em Tempo de Design

Código em tempo de design é implantado em conjuntos de módulos (assemblies) de metadados especiais.Para obter mais informações, consulte Como: Use o Repositório de Metadados.Para essa explicação passo a passo, o adorno personalizado é suportado somente pelo Visual Studio e é implantado em um conjunto de módulos (assembly) denominado CustomControlLibrary.VisualStudio.Design.

Para criando o conjunto de módulos (assembly) de metadados em tempo de design

  1. Adicione um novo projeto de biblioteca de classes no Visual Basic ou Visual C# denominado CustomControlLibrary.VisualStudio.Design à solução.

  2. conjunto caminho de saída do projeto para "..\CustomControlLibrary\bin\ ".Isso mantém o conjunto de módulos (assembly) do controle e o conjunto de módulos (assembly) de metadados na mesma pasta, o que permite a descoberta de metadados para os designers.

  3. Adicione referências para os seguintes conjuntos de módulos (assemblies) WPF.

    • PresentationCore

    • PresentationFramework

    • WindowsBase

  4. Adicione referências para os seguintes conjuntos de módulos (assemblies) WPF Designer:

    • Microsoft.Windows.Design

    • Microsoft.Windows.Design.Extensibility

    • Microsoft.Windows.Design.Interaction

  5. Adicione uma referência ao projeto CustomControlLibrary.

  6. Em Gerenciador de Soluções, altere o nome do arquivo de código Class1 para Metadata.cs ou Metadata.vb.

  7. Substitua o código gerado automaticamente pelo código a seguir.Esse código cria um AttributeTable que anexa a implementação personalizada em tempo de design à 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. Salve a solução.

Implementando o Provedor de Adorno.

O provedor de adorno é implementado em um tipo denominado InplaceButtonAdorners.Esta adorno permite que o usuário definia a propriedade Content do controle em tempo de design.

Para implementar o provedor de adorno.

  1. Adicione uma nova classe denominada InplaceButtonAdorners ao projeto CustomControlLibrary.Design.

  2. No Editor de Códigos de InplaceButtonAdorners, substitua o código gerado automaticamente pelo código a seguir.Esse código implementa um PrimarySelectionAdornerProvider que fornece uma adorno baseado em um controle 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. Crie a solução.

Testando a Implementação em Tempo de Design

Você pode usar o controle DemoControl do modo como você usaria qualquer outro controle WPF.O WPF Designer trata a criação de todos os objetos em tempo de design.

Para testar a implementação em tempo de design

  1. Adicione um novo projeto de aplicativo WPF no Visual C# denominado DemoApplication à solução.

    Window1.xaml é aberto no WPF Designer.

  2. Adicione uma referência ao projeto CustomControlLibrary.

  3. No modo de exibição XAML, substitua o XAML gerado automaticamente pelo seguinte XAML.Este XAML adiciona uma referência ao namespace CustomControlLibrary e adiciona o controle personalizado DemoControl.Se o botão não for exibido, talvez você precise clicar na Barra de Informações na parte superior do designer para recarregar o modo de exibição.

    <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. Recrie a solução.

  5. No modo Design, clique no controle DemoControl para selecioná-lo.

    Um pequeno Rectangle glifo é exibido no canto superior esquerdo das DemoControl controle.

  6. clicar no Rectangle glifo para ativar a edição in loco.

    Uma caixa de texto é exibida mostrando o Content de DemoControl. Como o conteúdo é vazio no momento, você verá apenas um cursor no centralizar do botão.

  7. Digite um novo valor para o conteúdo de texto e, em seguida, pressione a tecla ENTER.

    No modo de exibição XAML, a Content propriedade é conjunto para o valor de texto que você digitou no modo de modo de exibição de Design.

  8. conjunto projeto DemoApplication sistema autônomo o projeto de inicialização e executar a solução.

    Em time de execução, o botão tem o valor de texto definido com o adorno.

Próximas etapas

Você pode adicionar mais recursos em tempo de design personalizados para os controles personalizados.

Consulte também

Outros recursos

Criando personalizados editores

Extensibilidade do WPF Designer