2016-01-28 17 views
5

Próbuję napisać markupextension takiego:Czy TypeConverter być stosowany do argumentu konstruktora

[MarkupExtensionReturnType(typeof(Length))] 
public class LengthExtension : MarkupExtension 
{ 
    // adding the attribute like this compiles but does nothing. 
    public LengthExtension([TypeConverter(typeof(LengthTypeConverter))]Length value) 
    { 
     this.Value = value; 
    } 

    [ConstructorArgument("value")] 
    public Length Value { get; set; } 

    public override object ProvideValue(IServiceProvider serviceProvider) 
    { 
     return this.Value; 
    } 
} 

Aby być stosowany tak:

<Label Content="{units:Length 1 mm}" /> 

błądzi z:

TypConverter dla typu "Długość" nie obsługuje konwersji z łańcucha.

TypeConverter działa jeśli:

  • Umieścić go na własność Value i mieć domyślny konstruktor.
  • Udekoruj typ Length za pomocą atrybutu.

Chociaż może to być x/y Nie chcę żadnego z tych rozwiązań.

Oto kod dla przetwornika:

public class LengthTypeConverter : TypeConverter 
{ 
    public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) 
    { 
     if (sourceType == typeof(string)) 
     { 
      return true; 
     } 

     return base.CanConvertFrom(context, sourceType); 
    } 

    public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType) 
    { 
     if (destinationType == typeof(InstanceDescriptor) || destinationType == typeof(string)) 
     { 
      return true; 
     } 

     return base.CanConvertTo(context, destinationType); 
    } 

    public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) 
    { 
     var text = value as string; 
     if (text != null) 
     { 
      return Length.Parse(text, culture); 
     } 

     return base.ConvertFrom(context, culture, value); 
    } 

    public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType) 
    { 
     if (value is Length && destinationType != null) 
     { 
      var length = (Length)value; 
      if (destinationType == typeof(string)) 
      { 
       return length.ToString(culture); 
      } 
      else if (destinationType == typeof(InstanceDescriptor)) 
      { 
       var factoryMethod = typeof(Length).GetMethod(nameof(Length.FromMetres), BindingFlags.Public | BindingFlags.Static, null, new Type[] { typeof(double) }, null); 
       if (factoryMethod != null) 
       { 
        var args = new object[] { length.metres }; 
        return new InstanceDescriptor(factoryMethod, args); 
       } 
      } 
     } 

     return base.ConvertTo(context, culture, value, destinationType); 
    } 
} 

Odpowiedz

3

Od MSDN, Applying the TypeConverterAttribute kopalni (nacisk):

jeśli chcesz żeby konwerter typu custom być używany jako typ aktorstwa konwerter dla niestandardowej klasy przez procesor XAML, trzeba zastosować .NET Framework przypisują TypeConverterAttribute do klasy definicji ...

i

Można również dostarczyć konwerter typów na podstawie właściwości. Zamiast nakładania .NET Framework przypisują TypeConverterAttribute definicji klasy, stosuje się go do definicji własności ...

żadnej wzmianki o jakimkolwiek innym miejscu, aby zastosować atrybut. Tak więc odpowiedź na twoje pytanie jest bardzo prawdopodobne:

Nie, TypeConverter nie może być użyty dla argumentu konstruktora.

+0

Dziękuję panu, nie udało mi się googlować. Czy zdajesz sobie sprawę z tego, jak wiele niejawnej konwersji, która powoduje zastosowanie atrybutu do definicji klasy? Może to kolejne pytanie. A może [czat] (http://chat.stackoverflow.com/rooms/18165/wpf) –

+0

Nie jestem pewien, co oznacza "jak wiele niejawnej konwersji". Ale jeśli zastosujesz atrybut do typu Długość, konwersja będzie miała miejsce za każdym razem, gdy ustawisz Długość w XAML. – Clemens

+0

Włącza również powiązania. Może rzeczy takie jak serializacja. Nie jestem wielkim fanem niejawnej konwersji :) –

2

Delegowanie to na krytykę:

[MarkupExtensionReturnType(typeof(Length))] 
public class LengthExtension : MarkupExtension 
{ 
    public LengthExtension(string value) 
    { 
     this.Value = Length.Parse(value, CultureInfo.InvariantCulture); 
    } 

    public Length Value { get; private set; } 

    public override object ProvideValue(IServiceProvider serviceProvider) 
    { 
     return this.Value; 
    } 
} 

To działa, ale nie jestem pewien, czy są jakieś wady.

Powiązane problemy