다음을 통해 공유


연습: WPF Designer의 형식 변환기 만들기

이 연습에서는 사용자 지정 형식에 대한 형식 변환기를 만드는 방법을 보여 줍니다. WPF Designer for Visual Studio에서는 형식 변환기를 사용하여 사용자 지정 형식을 XAML(xtensible Application Markup Language)로 serialize하거나 deserialize합니다.

이 연습에서는 다음 작업을 수행합니다.

  • 프로젝트를 만듭니다.

  • 사용자 지정 형식을 만듭니다.

  • 형식 변환기를 만듭니다.

  • 사용자 지정 형식을 사용하는 컨트롤을 만듭니다.

  • 속성 창에서 사용자 지정 형식을 봅니다.

이 연습을 마치면 고유의 사용자 지정 형식에 대한 형식 변환기를 만들 수 있습니다.

참고

표시되는 대화 상자와 메뉴 명령은 활성 설정이나 버전에 따라 도움말에서 설명하는 것과 다를 수 있습니다. 설정을 변경하려면 도구 메뉴에서 설정 가져오기 및 내보내기를 선택합니다. 자세한 내용은 설정에 대한 작업을 참조하십시오.

사전 요구 사항

이 연습을 완료하려면 다음 구성 요소가 필요합니다.

  • Visual Studio 2010.

프로젝트 만들기

첫 번째 단계는 응용 프로그램의 프로젝트를 만드는 것입니다.

프로젝트를 만들려면

사용자 지정 형식 만들기

이 절차에서는 복소수를 나타내는 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. 파일 위쪽에서, TypeConverter 구현이 포함된 System.ComponentModel 네임스페이스를 가져옵니다.

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

사용자 지정 형식을 사용하는 컨트롤 만들기

사용자 지정 형식 및 해당 형식 변환기가 작동하는 방법을 디자인 화면에서 보려면 Complex 형식의 속성을 사용하여 UserControl을 만듭니다.

사용자 지정 형식을 사용하는 컨트롤을 만들려면

  1. ComplexNumberControl.xaml이라는 새 WPF 사용자 정의 컨트롤을 TypeConverterExample 프로젝트에 추가합니다. 자세한 내용은 방법: 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 Designer에서 MainWindow.xaml을 엽니다.

  2. XAML 뷰에서 Window 요소를 다음 코드로 바꿉니다.

    <Window x:Class="TypeConverterExample.MainWindow"
        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

기타 리소스

WPF의 XAML

WPF Designer 확장성