Exemplarische Vorgehensweise: Erstellen eines Typkonverters für den WPF-Designer
Aktualisiert: November 2007
In dieser exemplarischen Vorgehensweise wird erläutert, wie Sie einen Typkonverter für einen benutzerdefinierten Typ erstellen. Der Windows Presentation Foundation (WPF)-Designer für Visual Studio verwendet den Typkonverter, um den benutzerdefinierten Typ in bzw. aus der Extensible Application Markup Language (XAML) zu serialisieren.
Im Verlauf dieser exemplarischen Vorgehensweise führen Sie folgende Aufgaben aus:
Erstellen des Projekts
Erstellen des benutzerdefinierten Typs
Erstellen des Typkonverters
Erstellen eines Steuerelements, das den benutzerdefinierten Typ verwendet
Anzeigen des benutzerdefinierten Typs im Eigenschaftenfenster
Nach Abschluss können Sie Typkonverter für die benutzerdefinierten Typen erstellen
Hinweis: |
---|
Je nach den aktiven Einstellungen bzw. der Version unterscheiden sich die Dialogfelder und Menübefehle auf Ihrem Bildschirm unter Umständen von den in der Hilfe beschriebenen. Klicken Sie zum Ändern der Einstellungen im Menü Extras auf Einstellungen importieren und exportieren. Weitere Informationen finden Sie unter Visual Studio-Einstellungen. |
Vorbereitungsmaßnahmen
Zum Durchführen dieser exemplarischen Vorgehensweise benötigen Sie die folgenden Komponenten:
- Visual Studio 2008.
Erstellen des Projekts
Zunächst muss das Projekt für die Anwendung erstellt werden.
So erstellen Sie das Projekt
Erstellen Sie ein neues WPF-Anwendungsprojekt in Visual Basic oder Visual C# mit dem Namen TypeConverterExample. Weitere Informationen finden Sie unter Gewusst wie: Erstellen eines neuen WPF-Anwendungsprojekts.
In WPF-Designer wird die Datei Window1.xaml geöffnet.
Erstellen des benutzerdefinierten Typs
In diesem Verfahren erstellen Sie einen einfachen benutzerdefinierten Typ mit dem Namen Complex, der eine komplexe Zahl darstellt. Eine komplexe Zahl hat einen reellen Teil und einen imaginären Teil, und diese werden als double-Eigenschaft verfügbar gemacht.
So erstellen Sie einen benutzerdefinierten Typ
Fügen Sie dem TypeConverterExample-Projekt eine neue Klasse mit dem Namen Complex.vb oder Complex.cs hinzu. Weitere Informationen finden Sie unter Gewusst wie: Hinzufügen neuer Projektelemente.
Die Codedatei für die Complex-Klasse wird im Code-Editor geöffnet.
Ersetzen Sie die Complex-Klassendefinition durch den folgenden Code.
<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())); } }
Erstellen des Typkonverters
Jetzt definieren Sie den Typkonverter für die Complex-Klasse. Die ComplexTypeConverter-Klasse konvertiert ein Complex-Objekt in seine Zeichenfolgendarstellung und zurück. Sie stellt auch eine Liste von Standardwerten bereit, die im Eigenschaftenfenster eines Designers angezeigt werden kann.
So erstellen Sie den Typkonverter
Fügen Sie nach der Complex-Klassendefinition den folgenden Code für die ComplexTypeConverter-Klasse ein.
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; } }
Importieren Sie oben in der Datei den System.ComponentModel-Namespace, der die TypeConverter-Implementierung enthält.
Imports System.ComponentModel Imports System.Globalization
using System.ComponentModel; using System.Globalization;
Erstellen eines Steuerelements, das den benutzerdefinierten Typ verwendet
Wenn Sie den benutzerdefinierten Typ und den zugehörigen Typkonverter auf der Entwurfsoberfläche in Aktion sehen möchten, erstellen Sie ein UserControl-Steuerelement mit einer Eigenschaft vom Typ Complex.
So erstellen Sie ein Steuerelement, das den benutzerdefinierten Typ verwendet
Fügen Sie dem TypeConverterExample-Projekt ein neues WPF-Benutzersteuerelement mit dem Namen ComplexNumberControl.xaml hinzu. Weitere Informationen finden Sie unter Gewusst wie: Hinzufügen von neuen Elementen zu einem WPF-Projekt.
Zeigen Sie den Code für ComplexNumberControl an.
Ersetzen Sie die ComplexNumberControl-Klassendefinition durch den folgenden Code.
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())); }
Erstellen Sie das Projekt.
Anzeigen des benutzerdefinierten Typs im Eigenschaftenfenster
Sie können den benutzerdefinierten Typ anzeigen, wenn das ComplexNumberControl-Element in einem WPF-Fenster gehostet wird.
So zeigen Sie den benutzerdefinierten Typ im Eigenschaftenfenster an
Öffnen Sie im WPF-Designer die Datei Window1.xaml.
Ersetzen Sie in der XAML-Ansicht das Window-Element durch den folgenden Code.
<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>
Klicken Sie in der Entwurfsansicht. Falls notwendig, klicken Sie auf die Informationsleiste oben, um das Fenster erneut zu laden.
Klicken Sie in der XAML-Ansicht auf das ComplexNumberControl-Element.
Klicken Sie im Eigenschaftenfenster auf die ComplexNumber-Eigenschaft.
Neben dem ComplexNumber-Element wird ein Dropdownpfeil angezeigt.
Klicken Sie auf den Dropdownpfeil, um die Liste der Standardwerte anzuzeigen. Wählen Sie den Wert -1, -1 aus.
In der XAML-Ansicht ändert sich die ComplexNumber-Zuweisung in "-1,-1".
Siehe auch
Aufgaben
Gewusst wie: Implementieren eines Typkonverters