逐步解說:為 WPF 設計工具建立型別轉換子
本逐步解說顯示如何建立自訂型別的型別轉換子。 WPF Designer for Visual Studio 使用型別轉換子,將自訂型別序列化為 Extensible Application Markup Language (XAML),或從該語言序列化為自訂型別。
在這個逐步解說中,您會執行下列工作:
建立專案。
建立自訂型別。
建立型別轉換子。
建立使用自訂型別的控制項。
在 [屬性] 視窗中檢視自訂型別。
完成時,您就能夠為自己的自訂型別建立型別轉換子。
注意
根據您目前使用的設定或版本,您所看到的對話方塊與功能表指令可能會與 [說明] 中描述的不同。若要變更設定,請從 [工具] 功能表中選擇 [匯入和匯出設定]。如需詳細資訊,請參閱 Visual Studio 設定。
必要條件
您需要下列元件才能完成此逐步解說:
- Visual Studio 2012 RC.
建立專案
第一步就是建立應用程式的專案。
若要建立專案
在 Visual Basic 或 Visual C# 中,建立名為 TypeConverterExample 的新 WPF 應用程式專案。 如需詳細資訊,請參閱 HOW TO:建立新的 WPF 應用程式專案。
MainWindow.xaml 隨即在 WPF Designer中開啟。
建立自訂型別
在這個程序中,您會建立一個名為 Complex 的簡單自訂型別來代表複數。 複數有真實的部分和虛構的部分,這些部分會公開為 double 屬性。
若要建立自訂型別
將名為 Complex.vb 或 Complex.cs 的新類別加入到 TypeConverterExample 專案。 如需詳細資訊,請參閱 How to: Add New Project Items。
Complex 類別的程式碼檔案會在程式碼編輯器中開啟。
將 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 物件轉換成其字串表示以及將其轉換回來。 它也會提供預設值清單,這可顯示在設計工具的 [屬性] 視窗中。
若要建立型別轉換子
在 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; } }
在檔案的最上方,匯入 System.ComponentModel 命名空間,這其中包含 TypeConverter 實作。
Imports System.ComponentModel Imports System.Globalization
using System.ComponentModel; using System.Globalization;
建立使用自訂型別的控制項
為檢視自訂型別及其型別轉換子在設計介面上的實際運作,您會建立一個 UserControl 以及型別為 Complex 的屬性。
若要建立使用自訂型別的控制項
將名為 ComplexNumberControl.xaml 的新 WPF 使用者控制項加入到 TypeConverterExample 專案。 如需詳細資訊,請參閱 HOW TO:加入新項目至 WPF 專案。
檢視 ComplexNumberControl 的程式碼。
將 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())); }
建置專案。
在屬性視窗中檢視自訂型別
當 ComplexNumberControl 裝載在 WPF 視窗中時,您就可以檢視自訂型別。
若要在屬性視窗中檢視自訂型別
在 WPF Designer中開啟 MainWindow.xaml。
在 [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>
按一下 [設計] 檢視。 如有必要,按一下頂端的資訊列,重新載入視窗。
在 [XAML] 檢視中,按一下 ComplexNumberControl 項目。
在 [屬性] 視窗中,按一下 ComplexNumber 屬性。
ComplexNumber 項目旁會出現下拉箭號。
按一下下拉箭號,檢視預設值清單。 選取 [-1,-1] 值。
在 [XAML] 檢視中,ComplexNumber 指派 (Assignment) 會變更為 "-1,-1"。