更新 : 2007 年 11 月
Windows Presentation Foundation (WPF) Designer for Visual Studio の機能拡張モデルを使用すると、[プロパティ] ウィンドウ内のプロパティを操作するためのカスタムの値エディタをデザイン時に作成できます。作成できるのは、インライン エディタまたは拡張エディタです。インライン エディタは、[プロパティ] ウィンドウで値を直接編集できるエディタです。拡張エディタは、[プロパティ] ウィンドウの外部でプロパティを編集する UI を備えたエディタです。拡張エディタを作成する方法を示すために、このチュートリアルでは、コントロールの Background プロパティを操作するためのカラー エディタを作成する手順を説明します。この拡張エディタは、[プロパティ] ウィンドウのインライン エディタから開かれます。
このチュートリアルでは次のタスクを行います。
WPF カスタム コントロール プロジェクトを作成する。
拡張エディタとして動作するユーザー コントロールを作成する。
[プロパティ] ウィンドウのプロパティ値を編集したり拡張エディタを開いたりするために使用できるインライン エディタを作成する。
カスタム エディタを提供するクラスにエディタを接続するために使用する ExtendedPropertyValueEditor 派生クラスを作成する。
新しい拡張エディタを登録するために IRegisterMetadata 派生クラスを作成する。
デザイン時に拡張エディタをテストする。
前提条件
このチュートリアルを完了するには、次のコンポーネントが必要です。
- Visual Studio 2008。
カスタム コントロールの作成
最初に、カスタム コントロールのプロジェクトを作成します。コントロールは、デザイン時コードが少量のシンプルなボタンにします。このボタンは、GetIsInDesignMode メソッドを使用して、デザイン時動作を実装します。
カスタム コントロールを作成するには
Visual C# で CustomControlLibrary という名前の新しい WPF カスタム コントロール ライブラリ プロジェクトを作成します。
コード エディタで CustomControl1 のコードが開きます。
次の WPF デザイナ アセンブリへの参照を追加します。
- Microsoft.Windows.Design
CustomControl1 のコード エディタで、CustomControlLibrary 名前空間のコードを次のコードに置き換えます。
public class CustomControl1 : Button { public CustomControl1() { if (System.ComponentModel.DesignerProperties.GetIsInDesignMode(this)) { Background = Brushes.Red; } } }
プロジェクトの出力パスを "bin\" に設定します。
ソリューションをビルドします。
拡張エディタのユーザー コントロールの作成
前の手順で作成したコントロールは、カスタムのカラー エディタのアタッチ先となるコントロールです。この手順では、拡張エディタとして動作する別のユーザー コントロールを作成します。
拡張エディタとして動作するユーザー コントロールを作成するには
Visual C# で CustomControlLibrary.Design という名前の新しい WPF カスタム コントロール ライブラリ プロジェクトをソリューションに追加します。
コード エディタで CustomControl1 のコードが開きます。
ソリューション エクスプローラで、CustomControl1 ファイルを CustomControlLibrary.Design プロジェクトから削除します。
次の WPF デザイナ アセンブリへの参照を追加します。
- Microsoft.Windows.Design
CustomControlLibrary プロジェクトへの参照を追加します。
プロジェクトの出力パスを "..\CustomControlLibrary\bin\" に設定します。これにより、コントロールのアセンブリとメタデータのアセンブリが同じフォルダ内に配置されるため、デザイナがメタデータを検出できます。
ColorsList という名前の新しいクラスを CustomControlLibrary.Design プロジェクトに追加します。
ColorsList のコード エディタで、自動的に生成されたコードを次のコードに置き換えます。
using System; using System.Linq; using System.Collections.Generic; using System.Text; using System.Windows.Media; using System.Reflection; using System.Collections.ObjectModel; namespace ColorsListNamespace { public class ColorsList : ObservableCollection<Color> { public ColorsList() { Type type = typeof(Colors); foreach (PropertyInfo propertyInfo in type.GetProperties(BindingFlags.Public | BindingFlags.Static)) { if (propertyInfo.PropertyType == typeof(Color)) { Add((Color)propertyInfo.GetValue(null, null)); } } } } }
CustomControlLibrary.Design プロジェクトに ColorsListControl という名前の新しいユーザー コントロール (WPF) を追加します。
ColorsListControl.xaml のコードがデザイナで開きます。
ColorsListControl.xaml の XAML ビューで、自動的に生成された XAML を次の XAML に置き換えます。
<UserControl x:Class="ColorsListNamespace.ColorsListControl" xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml" xmlns:Local="clr-namespace:ColorsListNamespace" xmlns:PropertyEditing="clr-namespace:Microsoft.Windows.Design.PropertyEditing;assembly=Microsoft.Windows.Design" Height="184" Width="260" Background="White"> <UserControl.Resources> <Local:ColorsList x:Key="colors"/> <Style TargetType="{x:Type Button}"> <EventSetter Event="Click" Handler="ItemsControl_Click"/> </Style> </UserControl.Resources> <ItemsControl ItemsSource="{Binding Source={StaticResource colors}}" HorizontalContentAlignment="Stretch" VerticalContentAlignment="Stretch" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"> <ItemsControl.Template> <ControlTemplate TargetType="ItemsControl"> <Border CornerRadius="5" > <WrapPanel Orientation="Horizontal" VerticalAlignment="Center" HorizontalAlignment="Center"> <ScrollViewer> <ItemsPresenter/> </ScrollViewer> </WrapPanel> </Border> </ControlTemplate> </ItemsControl.Template> <ItemsControl.ItemsPanel> <ItemsPanelTemplate> <WrapPanel/> </ItemsPanelTemplate> </ItemsControl.ItemsPanel> <ItemsControl.ItemTemplate> <DataTemplate> <Button Tag="{Binding}" Command="{x:Static PropertyEditing:PropertyValueEditorCommands.ShowInlineEditor}"> <Button.Template> <ControlTemplate> <Border Width="30" Height="30" BorderBrush="Black" BorderThickness="1" CornerRadius="5"> <Rectangle Width="22" Height="22" ToolTip="{Binding}"> <Rectangle.Fill> <SolidColorBrush Color="{Binding}"/> </Rectangle.Fill> </Rectangle> </Border> </ControlTemplate> </Button.Template> </Button> </DataTemplate> </ItemsControl.ItemTemplate> </ItemsControl> </UserControl>
ソリューション エクスプローラで、ColorsListControl.xaml を展開し、ColorsListControl.xaml.cs を開きます。
ColorsListControl のコード エディタで、自動的に生成されたコードを次のコードに置き換えます。
using System; using System.Linq; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Text; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Navigation; using System.Windows.Shapes; namespace ColorsListNamespace { public partial class ColorsListControl : System.Windows.Controls.UserControl { public static readonly RoutedEvent ClosePopupEvent = EventManager.RegisterRoutedEvent("ClosePopupEvent", RoutingStrategy.Direct, typeof(RoutedEventHandler), typeof(ColorsListControl)); public ColorsListControl() { InitializeComponent(); } public static readonly DependencyProperty SelectedColorProperty = DependencyProperty.Register("SelectedColor", typeof(Color), typeof(ColorsListControl), new FrameworkPropertyMetadata(null)); public Color SelectedColor { get { return (Color)base.GetValue(SelectedColorProperty); } set { base.SetValue(SelectedColorProperty, value); } } public static readonly DependencyProperty SelectedBrushProperty = DependencyProperty.Register("SelectedBrush", typeof(SolidColorBrush), typeof(ColorsListControl), new FrameworkPropertyMetadata(null)); public SolidColorBrush SelectedBrush { get { return (SolidColorBrush)base.GetValue(SelectedBrushProperty); } set { base.SetValue(SelectedBrushProperty, value); } } public event RoutedEventHandler ClosePopup { add { AddHandler(ClosePopupEvent, value); } remove { RemoveHandler(ClosePopupEvent, value); } } protected void RaiseClosePopupEvent() { RoutedEventArgs newEventArgs = new RoutedEventArgs(ColorsListControl.ClosePopupEvent); RaiseEvent(newEventArgs); } private void ItemsControl_Click(object sender, RoutedEventArgs e) { SelectedColor = (Color)((Button)sender).Tag; SelectedBrush = new SolidColorBrush(SelectedColor); RaiseClosePopupEvent(); } } }
ソリューションをビルドします。
ColorsListControl.xaml をデザイナに再度読み込みます。拡張エディタ UI がデザイン ビューに表示されます。
カラー エディタのテンプレートの作成
カラー エディタのインライン エディタは、拡張エディタほど複雑ではなく、XAML データ テンプレートを使用して作成できます。また、前の手順で作成したユーザー コントロールを使用するよう指定するデータ テンプレートも拡張エディタ用に作成します。
カラー エディタのテンプレートを作成するには
EditorResources という名前の新しいクラスを CustomControlLibrary.Design プロジェクトに追加します。
EditorResources のコード エディタで、自動的に生成されたコードを次のコードに置き換えます。
namespace ExtendedEditorNamespace { using System; using System.Collections.Generic; using System.Text; using System.Windows; public partial class EditorResources : ResourceDictionary { public EditorResources() : base() { InitializeComponent(); } } }
[プロジェクト] メニューの [リソース ディクショナリの追加] をクリックします。
フォームに EditorResources.xaml という名前を付け、[追加] をクリックします。
EditorResources.xaml のコードがデザイナで開きます。
EditorResources.xaml の XAML ビューで、自動的に生成された XAML を次の XAML に置き換えます。
<ResourceDictionary xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml" xmlns:PropertyEditing="clr-namespace:Microsoft.Windows.Design.PropertyEditing;assembly=Microsoft.Windows.Design" xmlns:Local="clr-namespace:ColorsListNamespace" xmlns:Media="clr-namespace:System.Windows.Media;assembly=PresentationCore" xmlns:sys="clr-namespace:System;assembly=mscorlib" x:Class="ExtendedEditorNamespace.EditorResources"> <DataTemplate x:Key="BrushExtendedEditorTemplate"> <Local:ColorsListControl SelectedBrush="{Binding Value, Mode=TwoWay}"/> </DataTemplate> <DataTemplate x:Key="BrushInlineEditorTemplate"> <Grid> <Grid.ColumnDefinitions> <ColumnDefinition Width="1*"/> <ColumnDefinition Width="Auto"/> </Grid.ColumnDefinitions> <TextBox Grid.Column="0" Text="{Binding StringValue}"/> <PropertyEditing:EditModeSwitchButton Grid.Column="1"/> </Grid> </DataTemplate> </ResourceDictionary>
ソリューションをビルドします。
テンプレートのカプセル化とエディタの登録
作業は山を越えました。カラー エディタ用の拡張エディタ テンプレートとインライン エディタ テンプレートの作成が完了したので、これらをカプセル化するクラスを作成し、カスタム コントロールに登録できます。
エディタをカプセル化および登録するには
BrushExtendedEditor という名前の新しいクラスを CustomControlLibrary.Design プロジェクトに追加します。
BrushExtendedEditor のコード エディタで、自動的に生成されたコードを次のコードに置き換えます。
namespace ExtendedEditorNamespace { using System; using System.Collections.Generic; using System.Text; using Microsoft.Windows.Design.PropertyEditing; using System.Windows; using ExtendedEditorNamespace; public class BrushExtendedEditor : ExtendedPropertyValueEditor { private EditorResources res = new EditorResources(); public BrushExtendedEditor() { this.ExtendedEditorTemplate = res["BrushExtendedEditorTemplate"] as DataTemplate; this.InlineEditorTemplate = res["BrushInlineEditorTemplate"] as DataTemplate; } } }
Metadata という名前の新しいクラスを CustomControlLibrary.Design プロジェクトに追加します。
Metadata のコード エディタで、自動的に生成されたコードを次のコードに置き換えます。
namespace ExtendedEditorNamespace { using System; using System.Collections.Generic; using System.Text; using Microsoft.Windows.Design.Metadata; using System.ComponentModel; using Microsoft.Windows.Design.PropertyEditing; using System.Windows.Media; using System.Windows.Controls; using System.Windows; using CustomControlLibrary; // Container for any general design-time metadata that we want to initialize. // Designers will look for a type in the design-time assembly that implements IRegisterMetadata. // If found, they will instantiate it and call its Register() method automatically. internal class Metadata : IRegisterMetadata { // Called by Cider to register any design-time metadata public void Register() { AttributeTableBuilder builder = new AttributeTableBuilder(); builder.AddCustomAttributes (typeof(CustomControl1), Control.BackgroundProperty, PropertyValueEditor.CreateEditorAttribute( typeof(BrushExtendedEditor))); MetadataStore.AddAttributeTable(builder.CreateTable()); } } }
ソリューションをビルドします。
カラー エディタのテスト
カラー エディタの作成が完了しました。後はテストするだけです。エディタをテストするには、WPF アプリケーション プロジェクトをソリューションに追加し、カスタム コントロールを追加します。その後、[プロパティ] ウィンドウで背景色を変更し、新しいエディタの動作を確認します。
カラー エディタをテストするには
Visual C# の DemoApplication という名前の WPF アプリケーション プロジェクトをソリューションに追加します。
WPF デザイナで Window1.xaml が開きます。
CustomControlLibrary プロジェクトへの参照を追加します。
Window1.xaml の XAML ビューで、自動的に生成された XAML を次の XAML に置き換えます。この XAML により、CustomControlLibrary 名前空間への参照が追加され、CustomControl1 カスタム コントロールが追加されます。ボタンは、赤い背景色でデザイン ビューに表示されます。これは、コントロールがデザイン モードであることを示します。ボタンが表示されない場合は、デザイナの一番上の情報バーをクリックして、ビューの再読み込みを行う必要があります。
<Window x:Class="DemoApplication.Window1" xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml" Title="Window1" Height="300" Width="300" xmlns:my="clr-namespace:CustomControlLibrary;assembly=CustomControlLibrary"> <Grid> <my:CustomControl1 Margin="30,30,30,30" Name="customControl11">Button</my:CustomControl1> </Grid> </Window>
デザイナ ビューでコントロールを選択します。
[プロパティ] ウィンドウで、Background プロパティの横にあるドロップダウン ボタンをクリックします。既定の色リストの代わりに、ビジュアルなカラー エディタが表示されます。
エディタから色を選択します。カスタム コントロールの背景が、その色に変更されます。