Binding converter as inner class?
I was thinking about this problem again, and I came up with something similar to Dennis's solution : create a "proxy" converter class, with a Type property, which will create the instance of the actual converter and delegate the conversion to it.
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}
You use it like that :
<Window.Resources> <my:Converter x:Key="CornerRadiusConverter" Type="{x:Type controls:MyPanel+CornerRadiusConverter}"/></Window.Resources>
It could be possible. A few months ago I wrote a markup extension to create the converter for you inline. It keeps a dictionary of weak references so that you don't create multiple instances of the same converter. Handles creating converters with different arguments too.
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; } }}
What I do is:
<Window.Resources> <ResourceDictionary> <Converters:BooleanNotConverter x:Key="BooleanNotConverter"/> </ResourceDictionary></Window.Resources>
And then in the control
<CheckBox IsChecked="{Binding Path=BoolProperty, Converter={StaticResource BooleanNotConverter} />