次の方法で共有


チュートリアル : 埋め込み先編集の実装

更新 : 2007 年 11 月

このチュートリアルでは、Windows Presentation Foundation (WPF) カスタム コントロールに対して埋め込み先編集の機能を実装する方法について説明します。Windows Presentation Foundation (WPF) Designer for Visual Studio のこのデザイン時機能を使用すると、カスタム ボタン コントロールの Content プロパティ値を設定できます。このチュートリアルでは、コントロールは単純なボタンであり、装飾は、ボタンのコンテンツを変更できるテキスト ボックスです。

このチュートリアルでは次のタスクを行います。

  • WPF カスタム コントロール ライブラリ プロジェクトを作成する。

  • デザイン時メタデータに対する個別のアセンブリを作成する。

  • 埋め込み先編集用の装飾プロバイダを実装する。

  • デザイン時にコントロールをテストする。

このチュートリアルを終了すると、カスタム コントロール用の装飾プロバイダを作成する方法を習得できます。

Bb907383.alert_note(ja-jp,VS.90).gifメモ :

使用している設定またはエディションによっては、表示されるダイアログ ボックスやメニュー コマンドがヘルプに記載されている内容と異なる場合があります。設定を変更するには、[ツール] メニューの [設定のインポートとエクスポート] をクリックします。詳細については、「Visual Studio の設定」を参照してください。

前提条件

このチュートリアルを完了するには、次のコンポーネントが必要です。

  • Visual Studio 2008.

カスタム コントロールの作成

最初に、カスタム コントロールのプロジェクトを作成します。コントロールは、デザイン時コードが少量のシンプルなボタンにします。このボタンは、GetIsInDesignMode メソッドを使用して、デザイン時動作を実装します。

カスタム コントロールを作成するには

  1. Visual C# で CustomControlLibrary という名前の新しい WPF カスタム コントロール ライブラリ プロジェクトを作成します。

    コード エディタで CustomControl1 のコードが開きます。

  2. ソリューション エクスプローラで、コード ファイル名を DemoControl.cs に変更します。このプロジェクト内のすべての参照について名前を変更するかどうかをたずねるメッセージ ボックスが開いたら、[はい] をクリックします。

  3. ソリューション エクスプローラで、Themes フォルダを展開します。

  4. Generic.xaml をダブルクリックします。

    WPF デザイナで Generic.xaml が開きます。

  5. XAML ビューで、"CustomControl1" の出現箇所をすべて "DemoControl" に置き換えます。

  6. コード エディタで DemoControl.cs を開きます。

  7. 自動的に生成されたコードを次のコードに置き換えます。DemoControl カスタム コントロールは、Button を継承します。

    using System;
    using System.Windows;
    using System.Windows.Controls;
    
    namespace CustomControlLibrary
    {
        public class DemoControl : Button
        {   
        }
    }
    
  8. プロジェクトの出力パスを "bin\" に設定します。

  9. ソリューションをビルドします。

デザイン時メタデータ アセンブリの作成

デザイン時コードは、特殊なメタデータ アセンブリに配置されます。詳細については、「方法 : メタデータ ストアの使用方法」を参照してください。このチュートリアルでは、カスタム装飾は Visual Studio によってのみサポートされ、CustomControlLibrary.VisualStudio.Design という名前のアセンブリに配置されます。

デザイン時メタデータ アセンブリを作成するには

  1. Visual C# の CustomControlLibrary.VisualStudio.Design という名前の新しいクラス ライブラリ プロジェクトをソリューションに追加します。

  2. プロジェクトの出力パスを "..\CustomControlLibrary\bin\" に設定します。これにより、コントロールのアセンブリとメタデータのアセンブリが同じフォルダ内に配置されるため、デザイナがメタデータを検出できます。

  3. 次の WPF アセンブリへの参照を追加します。

    • PresentationCore

    • PresentationFramework

    • WindowsBase

  4. 次の WPF デザイナ アセンブリへの参照を追加します。

    • Microsoft.Windows.Design

    • Microsoft.Windows.Design.Extensibility

    • Microsoft.Windows.Design.Interaction

  5. CustomControlLibrary プロジェクトへの参照を追加します。

  6. ソリューション エクスプローラで、Class1 コード ファイル名を Metadata.cs に変更します。

  7. 自動的に生成されたコードを次のコードに置き換えます。このコードにより、カスタム デザイン時実装を DemoControl クラスに関連付ける AttributeTable が作成されます。

    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. ソリューションを保存します。

装飾プロバイダの実装

装飾プロバイダは InplaceButtonAdorners という名前の型で実装されます。この装飾プロバイダにより、コントロールの Content プロパティをデザイン時に設定できるようになります。

装飾プロバイダを実装するには

  1. InplaceButtonAdorners という名前の新しいクラスを CustomControlLibrary.VisualStudio.Design プロジェクトに追加します。

  2. InplaceButtonAdorners のコード エディタで、自動的に生成されたコードを次のコードに置き換えます。このコードにより、TextBox コントロールに基づく装飾を提供する PrimarySelectionAdornerProvider を実装します。

    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. ソリューションをビルドします。

デザイン時実装のテスト

DemoControl クラスは、他の WPF コントロールと同じように使用できます。WPF デザイナは、すべてのデザイン時オブジェクトの作成を処理します。

デザイン時実装をテストするには

  1. Visual C# の DemoApplication という名前の WPF アプリケーション プロジェクトをソリューションに追加します。

    WPF デザイナで Window1.xaml が開きます。

  2. CustomControlLibrary プロジェクトへの参照を追加します。

  3. XAML ビューで、自動的に生成された XAML を次の XAML に置き換えます。この XAML により、CustomControlLibrary 名前空間への参照が追加され、DemoControl カスタム コントロールが追加されます。コントロールが表示されない場合は、デザイナの一番上の情報バーをクリックして、ビューの再読み込みを行う必要があります。

    <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. ソリューションをビルドし直します。

  5. デザイン ビューで、DemoControl コントロールをクリックして選択します。

    小さな Rectangle グリフが DemoControl コントロールの左上端に表示されます。

  6. Rectangle グリフをクリックして、埋め込み先編集を有効にします。

    DemoControl の Content を示すテキスト ボックスが表示されます。今は、内容は空であるため、単にボタンの中央にカーソルが表示されるだけです。

  7. テキスト コンテンツの新しい値を入力して、Enter キーを押します。

    XAML ビュー内の Content プロパティは、デザイン ビューで入力したテキスト値に設定されます。

  8. DemoApplication プロジェクトをスタートアップ プロジェクトとして設定し、ソリューションを実行します。

    実行時には、装飾で設定したテキスト値がボタンに表示されます。

次の手順

カスタム コントロールに、さらにカスタム デザイン時機能を追加できます。

参照

その他の技術情報

カスタム エディタの作成

WPF デザイナの機能拡張