次の方法で共有


チュートリアル : MenuAction の作成

更新 : 2007 年 11 月

このチュートリアルでは、WPF (Windows Presentation Foundation) カスタム コントロール用のデザイン時メニュー プロバイダを作成する方法について説明します。このショートカット メニュー項目を使用して、カスタム ボタン コントロールの Background プロパティ値を設定できます。完全なコードの一覧については、「方法 : MenuAction を作成する」を参照してください。

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

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

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

  • メニュー プロバイダを実装する。

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

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

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

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

前提条件

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

  • Visual Studio 2008.

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

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

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

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

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

  2. ソリューション エクスプローラで、コード ファイル名を ButtonWithDesignTime.cs または ButtonWithDesignTime.vb に変更します。このプロジェクト内のすべての参照に対する名前を変更するかどうかを確認するメッセージが表示されたら、[はい] をクリックします。

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

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

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

  5. XAML ビューで、すべての "CustomControl1" を "ButtonWithDesignTime" に置き換えます。

  6. コード エディタで ButtonWithDesignTime.cs または ButtonWithDesignTime.vb を開きます。

  7. 自動的に生成されたコードを次のコードで置き換えます。このコードは、Button からの継承で、ボタンがデザイナに表示されると、"Design mode active" というテキストが表示されます。

    Imports System
    Imports System.Collections.Generic
    Imports System.Text
    Imports System.Windows.Controls
    Imports System.Windows.Media
    Imports System.ComponentModel
    
    Public Class ButtonWithDesignTime
        Inherits Button
    
        Public Sub New()
            ' The GetIsInDesignMode check and the following design-time 
            ' code are optional and shown only for demonstration.
            If DesignerProperties.GetIsInDesignMode(Me) Then
                Content = "Design mode active"
            End If
    
        End Sub
    End Class
    
    using System;
    using System.Collections.Generic;
    using System.Text;
    using System.Windows.Controls;
    using System.Windows.Media;
    using System.ComponentModel;
    
    namespace CustomControlLibrary
    {
        public class ButtonWithDesignTime : Button
        {
            public ButtonWithDesignTime()
            {
                // The GetIsInDesignMode check and the following design-time 
                // code are optional and shown only for demonstration.
                if (DesignerProperties.GetIsInDesignMode(this))
                {
                    Content = "Design mode active";
                }
            }
        }
    }
    
  8. プロジェクトの出力パスを "bin\" に設定します。

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

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

デザイン時コードは、特殊なメタデータ アセンブリで配布されます。このチュートリアルでは、コンテキスト メニューの実装は、CustomControlLibrary.VisualStudio.Design という名前のアセンブリで配布されます。

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

  1. Visual Basic または 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 または Metadata.vb に変更します。このプロジェクト内のすべての参照について名前を変更するかどうかを確認するメッセージが表示されたら、[はい] をクリックします。

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

    Imports System
    Imports System.Collections.Generic
    Imports System.Text
    Imports System.ComponentModel
    Imports System.Windows.Media
    Imports System.Windows.Controls
    Imports System.Windows
    Imports CustomControlLibrary
    Imports Microsoft.Windows.Design.Features
    Imports Microsoft.Windows.Design.Metadata
    Imports CustomControlLibrary.VisualStudio.Design.SliderAdornerLib
    
    ' 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
    
        ' Called by the designer to register any design-time metadata.
        Public Sub Register() Implements IRegisterMetadata.Register
            Dim builder As New AttributeTableBuilder()
    
            ' Add the menu provider to the design-time metadata.
            builder.AddCustomAttributes(GetType(ButtonWithDesignTime), _
                                        New FeatureAttribute(GetType(CustomContextMenuProvider)))
    
            MetadataStore.AddAttributeTable(builder.CreateTable())
        End Sub
    
    End Class
    
    using System;
    using System.Collections.Generic;
    using System.Text;
    using System.ComponentModel;
    using System.Windows.Media;
    using System.Windows.Controls;
    using System.Windows;
    
    using CustomControlLibrary;
    using Microsoft.Windows.Design.Features;
    using Microsoft.Windows.Design.Metadata;
    using SliderAdornerLib;
    
    namespace CiderPropertiesTester
    {
        // 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 menu provider to the design-time metadata.
                builder.AddCustomAttributes(
                    typeof(ButtonWithDesignTime), 
                    new FeatureAttribute(typeof(CustomContextMenuProvider)));
    
                MetadataStore.AddAttributeTable(builder.CreateTable());
            }
        }
    }
    
  8. ソリューションを保存します。

メニュー プロバイダの実装

メニュー プロバイダは CustomContextMenuProvider という名前の型で実装されます。提供される MenuAction により、コントロールの Background プロパティをデザイン時に設定できるようになります。

メニュー プロバイダを実装するには

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

  2. CustomContextMenuProvider のコード エディタで、自動的に生成されたコードを次のコードに置き換えます。このコードにより、カスタム MenuAction を提供する PrimarySelectionContextMenuProvider を実装します。

    Imports System
    Imports System.Collections.Generic
    Imports System.Text
    Imports Microsoft.Windows.Design.Interaction
    Imports System.Windows
    Imports Microsoft.Windows.Design.Model
    Imports System.Windows.Controls
    Imports System.Windows.Media
    
    ' The CustomContextMenuProvider class provides two context menu items
    ' at design time. These are implemented with the MenuAction class.
    Class CustomContextMenuProvider
        Inherits PrimarySelectionContextMenuProvider
    
        Private setBackgroundToBlueMenuAction As MenuAction
        Private clearBackgroundMenuAction As MenuAction
    
        ' The provider's constructor sets up the MenuAction objects 
        ' and the the MenuGroup which holds them.
        Public Sub New()
    
            ' Set up the MenuAction which sets the control's 
            ' background to Blue.
            setBackgroundToBlueMenuAction = New MenuAction("Blue")
            setBackgroundToBlueMenuAction.Checkable = True
            AddHandler setBackgroundToBlueMenuAction.Execute, AddressOf SetBackgroundToBlue_Execute
    
            ' Set up the MenuAction which sets the control's 
            ' background to its default value.
            clearBackgroundMenuAction = New MenuAction("Cleared")
            clearBackgroundMenuAction.Checkable = True
            AddHandler clearBackgroundMenuAction.Execute, AddressOf ClearBackground_Execute
    
            ' Set up the MenuGroup which holds the MenuAction items.
            Dim backgroundFlyoutGroup As New MenuGroup("SetBackgroundsGroup", "Set Background")
    
            ' If HasDropDown is false, the group appears inline, 
            ' instead of as a flyout. Set to true.
            backgroundFlyoutGroup.HasDropDown = True
            backgroundFlyoutGroup.Items.Add(setBackgroundToBlueMenuAction)
            backgroundFlyoutGroup.Items.Add(clearBackgroundMenuAction)
            Me.Items.Add(backgroundFlyoutGroup)
    
            ' The UpdateItemStatus event is raised immediately before 
            ' this provider shows its tabs, which provides the opportunity 
            ' to set states.
            AddHandler UpdateItemStatus, AddressOf CustomContextMenuProvider_UpdateItemStatus
    
        End Sub
    
        ' The following method handles the UpdateItemStatus event.
        ' It sets the MenuAction states according to the state
        ' of the control's Background property. This method is
        ' called before the context menu is shown.
        Sub CustomContextMenuProvider_UpdateItemStatus( _
            ByVal sender As Object, _
            ByVal e As MenuActionEventArgs)
    
            ' Turn everything on, and then based on the value 
            ' of the BackgroundProperty, selectively turn some off.
            clearBackgroundMenuAction.Checked = False
            clearBackgroundMenuAction.Enabled = True
            setBackgroundToBlueMenuAction.Checked = False
            setBackgroundToBlueMenuAction.Enabled = True
    
            ' Get a ModelItem which represents the selected control. 
            Dim selectedControl As ModelItem = _
                e.Selection.PrimarySelection
    
            ' Get the value of the Background property from the ModelItem.
            Dim backgroundProperty As ModelProperty = _
                selectedControl.Properties(Control.BackgroundProperty)
    
            ' Set the MenuAction items appropriately.
            If Not backgroundProperty.IsSet Then
                clearBackgroundMenuAction.Checked = True
                clearBackgroundMenuAction.Enabled = False
            ElseIf backgroundProperty.ComputedValue.Equals(Brushes.Blue) Then
                setBackgroundToBlueMenuAction.Checked = True
                setBackgroundToBlueMenuAction.Enabled = False
            End If
    
        End Sub
    
        ' The following method handles the Execute event. 
        ' It sets the Background property to its default value.
        Sub ClearBackground_Execute( _
            ByVal sender As Object, _
            ByVal e As MenuActionEventArgs)
    
            Dim selectedControl As ModelItem = e.Selection.PrimarySelection
            selectedControl.Properties(Control.BackgroundProperty).ClearValue()
    
        End Sub
    
        ' The following method handles the Execute event. 
        ' It sets the Background property to Brushes.Blue.
        Sub SetBackgroundToBlue_Execute( _
            ByVal sender As Object, _
            ByVal e As MenuActionEventArgs)
    
            Dim selectedControl As ModelItem = e.Selection.PrimarySelection
            selectedControl.Properties(Control.BackgroundProperty).SetValue(Brushes.Blue)
    
        End Sub
    
    End Class
    
    using System;
    using System.Collections.Generic;
    using System.Text;
    using Microsoft.Windows.Design.Interaction;
    using System.Windows;
    using Microsoft.Windows.Design.Model;
    using System.Windows.Controls;
    using System.Windows.Media;
    
    namespace SliderAdornerLib
    {
        // The CustomContextMenuProvider class provides two context menu items
        // at design time. These are implemented with the MenuAction class.
        class CustomContextMenuProvider : PrimarySelectionContextMenuProvider
        {
            private MenuAction setBackgroundToBlueMenuAction;
            private MenuAction clearBackgroundMenuAction;
    
            // The provider's constructor sets up the MenuAction objects 
            // and the the MenuGroup which holds them.
            public CustomContextMenuProvider()
            {   
                // Set up the MenuAction which sets the control's 
                // background to Blue.
                setBackgroundToBlueMenuAction = new MenuAction("Blue");
                setBackgroundToBlueMenuAction.Checkable = true;
                setBackgroundToBlueMenuAction.Execute += 
                    new EventHandler<MenuActionEventArgs>(SetBackgroundToBlue_Execute);
    
                // Set up the MenuAction which sets the control's 
                // background to its default value.
                clearBackgroundMenuAction = new MenuAction("Cleared");
                clearBackgroundMenuAction.Checkable = true;
                clearBackgroundMenuAction.Execute += 
                    new EventHandler<MenuActionEventArgs>(ClearBackground_Execute);
    
                // Set up the MenuGroup which holds the MenuAction items.
                MenuGroup backgroundFlyoutGroup = 
                    new MenuGroup("SetBackgroundsGroup", "Set Background");
    
                // If HasDropDown is false, the group appears inline, 
                // instead of as a flyout. Set to true.
                backgroundFlyoutGroup.HasDropDown = true;
                backgroundFlyoutGroup.Items.Add(setBackgroundToBlueMenuAction);
                backgroundFlyoutGroup.Items.Add(clearBackgroundMenuAction);
                this.Items.Add(backgroundFlyoutGroup);
    
                // The UpdateItemStatus event is raised immediately before 
                // this provider shows its tabs, which provides the opportunity 
                // to set states.
                UpdateItemStatus += 
                    new EventHandler<MenuActionEventArgs>(
                        CustomContextMenuProvider_UpdateItemStatus);
            }
    
            // The following method handles the UpdateItemStatus event.
            // It sets the MenuAction states according to the state
            // of the control's Background property. This method is
            // called before the context menu is shown.
            void CustomContextMenuProvider_UpdateItemStatus(
                object sender, 
                MenuActionEventArgs e)
            {
                // Turn everything on, and then based on the value 
                // of the BackgroundProperty, selectively turn some off.
                clearBackgroundMenuAction.Checked = false;
                clearBackgroundMenuAction.Enabled = true;
                setBackgroundToBlueMenuAction.Checked = false;
                setBackgroundToBlueMenuAction.Enabled = true;
    
                // Get a ModelItem which represents the selected control. 
                ModelItem selectedControl = e.Selection.PrimarySelection;
    
                // Get the value of the Background property from the ModelItem.
                ModelProperty backgroundProperty = 
                    selectedControl.Properties[Control.BackgroundProperty];
    
                // Set the MenuAction items appropriately.
                if (!backgroundProperty.IsSet)
                {
                    clearBackgroundMenuAction.Checked = true;
                    clearBackgroundMenuAction.Enabled = false;
                }
                else if (backgroundProperty.ComputedValue == Brushes.Blue)
                {
                    setBackgroundToBlueMenuAction.Checked = true;
                    setBackgroundToBlueMenuAction.Enabled = false;
                }
            }
    
            // The following method handles the Execute event. 
            // It sets the Background property to its default value.
            void ClearBackground_Execute(
                object sender, 
                MenuActionEventArgs e)
            {
                ModelItem selectedControl = e.Selection.PrimarySelection;
                selectedControl.Properties[Control.BackgroundProperty].ClearValue();
            }
    
            // The following method handles the Execute event. 
            // It sets the Background property to Brushes.Blue.
            void SetBackgroundToBlue_Execute(
                object sender, 
                MenuActionEventArgs e)
            {
                ModelItem selectedControl = e.Selection.PrimarySelection;
                selectedControl.Properties[Control.BackgroundProperty].SetValue(Brushes.Blue);
            }
        }
    }
    
  3. ソリューションをビルドします。

デザイン時実装のテスト

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

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

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

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

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

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

    <Window x:Class="DemoApplication.Window1"
        xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:cc="clr-namespace:CustomControlLibrary;assembly=CustomControlLibrary"
        Title="Window1" Height="300" Width="300">
        <Grid>
            <cc:ButtonWithDesignTime Margin="30,30,30,30" Background="#FFD4D0C8"></cc:ButtonWithDesignTime>
        </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:cc="clr-namespace:CustomControlLibrary;assembly=CustomControlLibrary"
        Title="Window1" Height="300" Width="300">
        <Grid>
            <cc:ButtonWithDesignTime Margin="30,30,30,30" Background="#FFD4D0C8"></cc:ButtonWithDesignTime>
        </Grid>
    </Window>
    
  4. デザイン ビューで、ButtonWithDesignTime コントロールをクリックして選択します。

  5. ButtonWithDesignTime コントロールを右クリックし、[Set Background] をポイントして、[Blue] をクリックします。

    コントロールの背景が青に設定されます。XAML ビューで、Background プロパティは、メニュー アクションによって指定された値に設定されます。

  6. DemoApplication プロジェクトを実行します。

    実行時、ボタンは、ショートカット メニューで設定した背景になります。

次の手順

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

参照

処理手順

方法 : MenuAction を作成する

参照

PrimarySelectionContextMenuProvider

その他の技術情報

高度な機能拡張という概念

WPF デザイナの機能拡張