チュートリアル : WPF デザイナの型コンバータの作成

更新 : 2007 年 11 月

このチュートリアルでは、カスタムの型の型コンバータを作成する方法について説明します。Windows Presentation Foundation (WPF) Designer for Visual Studio は、カスタムの型から XAML (Extensible Application Markup Language) へのシリアル化およびその逆のシリアル化を行うために型コンバータを使用します。

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

  • プロジェクトを作成します。

  • カスタムの型を作成します。

  • 型コンバータを作成します。

  • カスタムの型を使用するコントロールを作成します。

  • [プロパティ] ウィンドウにカスタムの型を表示します。

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

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

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

前提条件

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

  • Visual Studio 2008.

プロジェクトの作成

最初にアプリケーションのプロジェクトを作成します。

プロジェクトを作成するには

カスタムの型の作成

この手順では、Complex という名前の簡単なカスタムの型を作成します。この型は複合型を表します。複合型は実数部と虚数部で構成され、これらは double プロパティとして公開されます。

カスタムの型を作成するには

  1. Complex.vb または Complex.cs という名前の新しいクラスを TypeConverterExample プロジェクトに追加します。詳細については、「方法 : 新しいプロジェクト項目を追加する」を参照してください。

    Complex クラスのコード ファイルがコード エディタで開かれます。

  2. Complex クラスの定義を次のコードに置き換えます。

    <TypeConverter(GetType(ComplexTypeConverter))> _
    Public Class Complex
        Private realValue As Double
        Private imaginaryValue As Double
    
        Public Sub New()
    
        End Sub
    
        Public Sub New(ByVal real As Double, ByVal imaginary As Double)
            Me.realValue = real
            Me.imaginaryValue = imaginary
    
        End Sub
    
        Public Property Real() As Double
            Get
                Return realValue
            End Get
    
            Set(ByVal value As Double)
                realValue = value
            End Set
        End Property
    
        Public Property Imaginary() As Double
            Get
                Return imaginaryValue
            End Get
    
            Set(ByVal value As Double)
                imaginaryValue = value
            End Set
        End Property
    
        Public Overrides Function ToString() As String
            Return String.Format( _
                CultureInfo.CurrentCulture, _
                "{0}{2}{1}", _
                Me.realValue, _
                Me.imaginaryValue, _
                CultureInfo.CurrentCulture.NumberFormat.NumberGroupSeparator)
        End Function
    
        Public Shared Function Parse(ByVal complexNumber As String) As Complex
            If String.IsNullOrEmpty(complexNumber) Then
                Return New Complex()
            End If
    
            'The parts array holds the real and imaginary parts of the object.
            Dim separator() As Char = {","}
            Dim parts() As String = complexNumber.Split(separator)
    
            If (parts.Length <> 2) Then
                Throw New FormatException( _
                    String.Format( _
                        "Cannot parse '{0}' into a Complex object because " & _
                        "it is not in the '<real>, <imaginary>' format.", _
                    complexNumber))
            End If
    
            Return New Complex( _
                Double.Parse(parts(0).Trim()), _
                Double.Parse(parts(1).Trim()))
    
        End Function
    
    End Class
    
    [TypeConverter( typeof( ComplexTypeConverter ) )]
    public class Complex
    {
        private double realValue;
        private double imaginaryValue;
    
        public Complex()
        {
        }
    
        public Complex(double real, double imaginary)
        {
            this.realValue = real;
            this.imaginaryValue = imaginary;
        }
    
        public double Real
        {
            get
            {
                return realValue;
            }
    
            set
            {
                realValue = value;
            }
        }
    
        public double Imaginary
        {
            get 
            {
                return imaginaryValue; 
            }
    
            set 
            {
                imaginaryValue = value; 
            }
        }
    
        public override string ToString()
        {
            return String.Format(
                CultureInfo.CurrentCulture, 
                "{0}{2}{1}", 
                this.realValue, 
                this.imaginaryValue,
                CultureInfo.CurrentCulture.NumberFormat.NumberGroupSeparator);
        }
    
        public static Complex Parse(string complexNumber)
        {
            if (String.IsNullOrEmpty(complexNumber))
            {
                return new Complex();
            }
    
            // The parts array holds the real and 
            // imaginary parts of the object.
            string[] parts = complexNumber.Split(',');       
    
            if (2 != parts.Length)
            {
                throw new FormatException(
                    String.Format(
                    "Cannot parse '{0}' into a Complex object because " +
                    "it is not in the \"<real>, <imaginary>\" format.",
                    complexNumber));
            }
    
            return new Complex(double.Parse(parts[0].Trim()), double.Parse(parts[1].Trim()));
    
        }
    }
    

型コンバータの作成

次に、Complex クラスの型コンバータを定義します。ComplexTypeConverter クラスは、Complex オブジェクトから文字列形式への変換およびその逆の変換を行います。また、既定値のリストも提供します。既定値は、デザイナの [プロパティ] ウィンドウで表示できます。

型コンバータを作成するには

  1. Complex クラス定義の後に次の ComplexTypeConverter クラスのコードを挿入します。

    Public Class ComplexTypeConverter
        Inherits TypeConverter
    
        Private Shared defaultValues As List(Of Complex) = New List(Of Complex)()
    
        Shared Sub New()
            defaultValues.Add(New Complex(0, 0))
            defaultValues.Add(New Complex(1, 1))
            defaultValues.Add(New Complex(-1, 1))
            defaultValues.Add(New Complex(-1, -1))
            defaultValues.Add(New Complex(1, -1))
        End Sub
    
        ' Override CanConvertFrom to return true for String-to-Complex conversions.
        Public Overrides Function CanConvertFrom( _
            ByVal context As ITypeDescriptorContext, _
            ByVal sourceType As Type) As Boolean
    
            If sourceType Is GetType(String) Then
                Return True
            End If
    
            Return MyBase.CanConvertFrom(context, sourceType)
    
        End Function
    
        ' Override CanConvertTo to return true for Complex-to-String conversions.
        Public Overrides Function CanConvertTo( _
            ByVal context As System.ComponentModel.ITypeDescriptorContext, _
            ByVal destinationType As System.Type) As Boolean
    
            If destinationType Is GetType(String) Then
                Return True
            End If
    
            Return MyBase.CanConvertTo(context, destinationType)
    
        End Function
    
        ' Override ConvertFrom to convert from a string to an instance of Complex.
        Public Overrides Function ConvertFrom( _
            ByVal context As ITypeDescriptorContext, _
            ByVal culture As System.Globalization.CultureInfo, _
            ByVal value As Object) As Object
    
            If TypeOf value Is String Then
                Try
                    Return Complex.Parse(CType(value, String))
                Catch ex As Exception
                    Throw New Exception( _
                        String.Format( _
                            "Cannot convert '{0}' ({1}) because {2}", _
                            value, _
                            value.GetType(), _
                            ex.Message), ex)
    
                End Try
            End If
    
            Return MyBase.ConvertFrom(context, culture, value)
    
        End Function
    
        ' Override ConvertTo to convert from an instance of Complex to string.
        Public Overrides Function ConvertTo( _
            ByVal context As ITypeDescriptorContext, _
            ByVal culture As System.Globalization.CultureInfo, _
            ByVal value As Object, _
            ByVal destinationType As Type) As Object
    
            If destinationType Is Nothing Then
                Throw New ArgumentNullException("destinationType")
            End If
    
            Dim c As Complex = CType(value, Complex)
    
            If (c IsNot Nothing) Then
                If Me.CanConvertTo(context, destinationType) Then
                    Return c.ToString()
                End If
            End If
    
            Return MyBase.ConvertTo(context, culture, value, destinationType)
    
        End Function
    
    
        Public Overrides Function GetStandardValuesSupported( _
            ByVal context As System.ComponentModel.ITypeDescriptorContext) As Boolean
    
            Return True
    
        End Function
    
    
        Public Overrides Function GetStandardValues( _
            ByVal context As System.ComponentModel.ITypeDescriptorContext) _
                As TypeConverter.StandardValuesCollection
    
            Dim svc As New StandardValuesCollection(defaultValues)
            Return svc
    
        End Function
    End Class
    
    public class ComplexTypeConverter : TypeConverter
    {
        private static List<Complex> defaultValues = new List<Complex>();
    
        static ComplexTypeConverter()
        {
            defaultValues.Add(new Complex(0, 0));
            defaultValues.Add(new Complex( 1, 1));
            defaultValues.Add(new Complex(-1, 1));
            defaultValues.Add(new Complex(-1,-1));
            defaultValues.Add(new Complex( 1,-1));
        }
    
        // Override CanConvertFrom to return true for String-to-Complex conversions.
        public override bool CanConvertFrom(
            ITypeDescriptorContext context, 
            Type sourceType)
        {
            if (sourceType == typeof(string))
            {
                return true;
            }
    
            return base.CanConvertFrom(context, sourceType);
        }
    
        // Override CanConvertTo to return true for Complex-to-String conversions.
        public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
        {
            if (destinationType == typeof(string))
            {
                return true;
            }
    
            return base.CanConvertTo(context, destinationType);
        }
    
        // Override ConvertFrom to convert from a string to an instance of Complex.
        public override object ConvertFrom(
            ITypeDescriptorContext context, 
            System.Globalization.CultureInfo culture, 
            object value)
        {
            string text = value as string;
    
            if (text != null)
            {
                try
                {
                    return Complex.Parse(text);
                }
                catch (Exception e)
                {
                    throw new Exception(
                        String.Format("Cannot convert '{0}' ({1}) because {2}", 
                                        value, 
                                        value.GetType(), 
                                        e.Message), e);
                }
            }
    
            return base.ConvertFrom(context, culture, value);
        }
    
        // Override ConvertTo to convert from an instance of Complex to string.
        public override object ConvertTo(
            ITypeDescriptorContext context, 
            System.Globalization.CultureInfo culture, 
            object value, 
            Type destinationType)
        {
            if (destinationType == null)
            {
                throw new ArgumentNullException("destinationType");
            }
    
            //Convert Complex to a string in a standard format.
            Complex c = value as Complex;
    
            if (c != null && this.CanConvertTo(context, destinationType))
            {
                return c.ToString();
            }
    
            return base.ConvertTo(context, culture, value, destinationType);
        }
    
        public override bool GetStandardValuesSupported(ITypeDescriptorContext context)
        {
            return true;
        }
    
        public override TypeConverter.StandardValuesCollection GetStandardValues(
            ITypeDescriptorContext context)
        {   
            StandardValuesCollection svc = new StandardValuesCollection(defaultValues);       
            return svc;
        }
    }
    
  2. ファイルの先頭で System.ComponentModel 名前空間をインポートします。ここには TypeConverter 実装が含まれています。

    Imports System.ComponentModel
    Imports System.Globalization
    
    using System.ComponentModel;
    using System.Globalization;
    

カスタムの型を使用するコントロールの作成

カスタムの型と型コンバータの動作をデザイン画面上で確認するために、Complex 型のプロパティを使用する UserControl を作成します。

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

  1. TypeConverterExample プロジェクトに ComplexNumberControl.xaml という名前の新しい WPF ユーザー コントロールを追加します。詳細については、「方法 : 新しい項目を WPF プロジェクトに追加する」を参照してください。

  2. ComplexNumberControl のコードを表示します。

  3. ComplexNumberControl クラスの定義を次のコードに置き換えます。

    Partial Public Class ComplexNumberControl
        Inherits System.Windows.Controls.UserControl
    
        Private complexNumberValue As Complex
    
        Public Sub New()
            InitializeComponent()
    
        End Sub
    
        Public Property ComplexNumber() As Complex
            Get
                Return Me.GetValue(ComplexNumberProperty)
            End Get
    
            Set(ByVal value As Complex)
                Me.SetValue(ComplexNumberProperty, value)
            End Set
        End Property
    
        Public Shared ReadOnly ComplexNumberProperty As DependencyProperty = DependencyProperty.Register( _
          "ComplexNumber", _
          GetType(Complex), _
          GetType(ComplexNumberControl), _
          New PropertyMetadata(New Complex()))
    
    End Class
    
    public partial class ComplexNumberControl : UserControl
    {
        public ComplexNumberControl()
        {
            InitializeComponent();
        }
    
        public Complex ComplexNumber
        {
            get 
            { 
                return (Complex)this.GetValue(ComplexNumberProperty); 
            }
    
            set 
            { 
                this.SetValue(ComplexNumberProperty, value); 
            }
        }
        public static readonly DependencyProperty ComplexNumberProperty = DependencyProperty.Register(
          "ComplexNumber",
          typeof(Complex),
          typeof(ComplexNumberControl),
          new PropertyMetadata(new Complex()));
    }
    
  4. プロジェクトをビルドします。

[プロパティ] ウィンドウにカスタムの型を表示する

ComplexNumberControl が WPF ウィンドウでホストされる場合は、カスタムの型を表示できます。

[プロパティ] ウィンドウにカスタムの型を表示するには

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

  2. XAML ビューで、Window 要素を次のコードに置き換えます。

    <Window x:Class="TypeConverterExample.Window1"
        xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:c="clr-namespace:TypeConverterExample"
        Title="Window1" Height="300" Width="300">
        <Grid>
            <c:ComplexNumberControl ComplexNumber="0,0" />
        </Grid>
    </Window>
    
    <Window x:Class="TypeConverterExample.Window1"
        xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:c="clr-namespace:TypeConverterExample"
        Title="Window1" Height="300" Width="300">
        <Grid>
            <c:ComplexNumberControl ComplexNumber="0,0" />
        </Grid>
    </Window>
    
  3. デザイン ビュー内をクリックします。必要に応じて、最上部の情報バーをクリックしてウィンドウを再度読み込みます。

  4. XAML ビューで、ComplexNumberControl 要素をクリックします。

  5. [プロパティ] ウィンドウで、ComplexNumber プロパティをクリックします。

    ドロップダウン矢印が ComplexNumber アイテムの横に表示されます。

  6. ドロップダウンをクリックして、既定値のリストを表示します。-1,-1 値を選択します。

    XAML ビューで、ComplexNumber の割り当てが "-1,-1" に変更されます。

参照

処理手順

方法 : 型コンバータを実装する

参照

TypeConverter

TypeConverterAttribute

XamlReader

XamlWriter

System.Windows.Markup

その他の技術情報

XAML

WPF デザイナの機能拡張