2009-05-14 14 views
8

Ich habe ein UserControl, das einen bindenden Konverter verwendet. Ich habe den Konverter eine innere Klasse vonBindewandler als innere Klasse?

gemacht
public partial class MyPanel : UserControl 
{ 
    public class CornerRadiusConverter : IValueConverter 
    { 

Wie referenziere ich die Converter-Klasse von der XAML? Die folgende funktioniert nicht:

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

Es gibt diesen Fehler:

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

+0

einfach eine normale Klasse verwenden! –

+2

@SergeyAldoukhov: Warum? Dieser Vorschlag ist nicht hilfreich. –

Antwort

2

Ich habe erneut über dieses Problem nachgedacht und kam zu etwas, das der Lösung von Dennis ähnlich ist: Erstellen Sie eine "Proxy" -Konverterklasse mit einer Type-Eigenschaft, die die Instanz des aktuellen Konverters erstellt und die Konvertierung an sie delegiert.

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 
} 

Sie verwenden es wie folgt aus:

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

es möglich sein könnte. Vor ein paar Monaten habe ich eine Markup-Erweiterung geschrieben, um den Konverter für dich inline zu erstellen. Es enthält ein Wörterbuch mit schwachen Referenzen, sodass Sie nicht mehrere Instanzen desselben Konverters erstellen. Griffe, die Konverter mit unterschiedlichen Argumenten auch verursachen.

In 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

Coole Idee! Ich bin ein großer Fan von benutzerdefinierten Markup-Erweiterungen selbst;) –

-3

Was ich tue, ist:

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

Und dann in der Steuer

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

Es löst nicht Robert Problem, das ist, dass seine Konverter-Klasse eine geschachtelte Klasse ist ... –

Verwandte Themen