2009-05-14 17 views
8

Mam UserControl, który używa konwertera powiązania. Przekształciłem konwerter w wewnętrzną klasę:Wiążący konwerter jako wewnętrzna klasa?

Jak mogę odnieść się do klasy Konwertera z XAML? Poniższa nie działa:

<controls:MyPanel.CornerRadiusConverter x:Key="CornerRadiusConverter" /> 

Daje ten błąd:

The tag 'LensPanel.CornerRadiusConverter' does not exist in XML namespace 'clr-namespace:MyApp.Windows.Controls'

+0

Wystarczy użyć normalnej klasy! –

+2

@SergeyAldoukhov: Dlaczego? Ta sugestia nie jest pomocna. –

Odpowiedz

2

Znów myślałem o tym problemie i wpadłem na coś podobnego do rozwiązania Dennisa: stwórz klasę konwertera "proxy", z właściwością Typ, która utworzy instancję rzeczywistego konwertera i przekaże konwersję do niego.

public class Converter : IValueConverter 
{ 
    private Type _type = null; 
    public Type Type 
    { 
     get { return _type; } 
     set 
     { 
      if (value != _type) 
      { 
       if (value.GetInterface("IValueConverter") != null) 
       { 
        _type = value; 
        _converter = null; 
       } 
       else 
       { 
        throw new ArgumentException(
         string.Format("Type {0} doesn't implement IValueConverter", value.FullName), 
         "value"); 
       } 
      } 
     } 
    } 

    private IValueConverter _converter = null; 
    private void CreateConverter() 
    { 
     if (_converter == null) 
     { 
      if (_type != null) 
      { 
       _converter = Activator.CreateInstance(_type) as IValueConverter; 
      } 
      else 
      { 
       throw new InvalidOperationException("Converter type is not defined"); 
      } 
     } 
    } 

    #region IValueConverter Members 

    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) 
    { 
     CreateConverter(); 
     return _converter.Convert(value, targetType, parameter, culture); 
    } 

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) 
    { 
     CreateConverter(); 
     return _converter.ConvertBack(value, targetType, parameter, culture); 
    } 

    #endregion 
} 

go używać tak:

<Window.Resources> 
    <my:Converter x:Key="CornerRadiusConverter" Type="{x:Type controls:MyPanel+CornerRadiusConverter}"/> 
</Window.Resources> 
2

To mogłoby być możliwe. Kilka miesięcy temu napisałem rozszerzenie znaczników, aby utworzyć konwerter dla Ciebie. Przechowuje słownik słabych odniesień, aby nie tworzyć wielu wystąpień tego samego konwertera. Obsługuje także tworzenie konwerterów z różnymi argumentami.

w XAML:

<TextBox Text="{Binding Converter={NamespaceForMarkupExt:InlineConverter {x:Type NamespaceForConverter:ConverterType}}}"/> 

C#:

[MarkupExtensionReturnType(typeof(IValueConverter))] 
public class InlineConverterExtension : MarkupExtension 
{ 
    static Dictionary<string, WeakReference> s_WeakReferenceLookup; 

    Type m_ConverterType; 
    object[] m_Arguments; 

    static InlineConverterExtension() 
    { 
    s_WeakReferenceLookup = new Dictionary<string, WeakReference>(); 
    } 

    public InlineConverterExtension() 
    { 
    } 

    public InlineConverterExtension(Type converterType) 
    { 
    m_ConverterType = converterType; 
    } 

    /// <summary> 
    /// The type of the converter to create 
    /// </summary> 
    /// <value>The type of the converter.</value> 
    public Type ConverterType 
    { 
    get { return m_ConverterType; } 
    set { m_ConverterType = value; } 
    } 

    /// <summary> 
    /// The optional arguments for the converter's constructor. 
    /// </summary> 
    /// <value>The argumments.</value> 
    public object[] Arguments 
    { 
    get { return m_Arguments; } 
    set { m_Arguments = value; } 
    } 

    public override object ProvideValue(IServiceProvider serviceProvider) 
    { 
    IProvideValueTarget target = (IProvideValueTarget)serviceProvider.GetService(typeof(IProvideValueTarget)); 

    PropertyInfo propertyInfo = target.TargetProperty as PropertyInfo; 

    if (!propertyInfo.PropertyType.IsAssignableFrom(typeof(IValueConverter))) 
     throw new NotSupportedException("Property '" + propertyInfo.Name + "' is not assignable from IValueConverter."); 

    System.Diagnostics.Debug.Assert(m_ConverterType != null, "ConverterType is has not been set, ConverterType{x:Type converterType}"); 

    try 
    { 
     string key = m_ConverterType.ToString(); 

     if (m_Arguments != null) 
     { 
     List<string> args = new List<string>(); 
     foreach (object obj in m_Arguments) 
      args.Add(obj.ToString()); 

     key = String.Concat(key, "_", String.Join("|", args.ToArray())); 
     } 

     WeakReference wr = null; 
     if (s_WeakReferenceLookup.TryGetValue(key, out wr)) 
     { 
     if (wr.IsAlive) 
      return wr.Target; 
     else 
      s_WeakReferenceLookup.Remove(key); 
     } 

     object converter = (m_Arguments == null) ? Activator.CreateInstance(m_ConverterType) : Activator.CreateInstance(m_ConverterType, m_Arguments); 
     s_WeakReferenceLookup.Add(key, new WeakReference(converter)); 

     return converter; 
    } 
    catch(MissingMethodException) 
    { 
     // constructor for the converter does not exist! 
     throw; 
    } 
    } 

} 
+0

Fajny pomysł! Sam jestem wielkim fanem niestandardowych rozszerzeń znaczników;) –

-3

Co mogę zrobić, to:

<Window.Resources> 
    <ResourceDictionary> 
    <Converters:BooleanNotConverter x:Key="BooleanNotConverter"/> 
    </ResourceDictionary> 
</Window.Resources> 

A potem w kontroli

<CheckBox IsChecked="{Binding Path=BoolProperty, Converter={StaticResource BooleanNotConverter} /> 
+0

To nie rozwiązuje problemu Roberta, który polega na tym, że jego klasa konwertera jest klasą zagnieżdżoną ... –

Powiązane problemy