Binding converter as inner class?

前端 未结 3 498
太阳男子
太阳男子 2020-12-19 04:52

I have a UserControl that uses a binding converter. I\'ve made the converter an inner class of

public partial class MyPanel : UserControl
{
    public class          


        
相关标签:
3条回答
  • 2020-12-19 05:30

    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;
        }
      }
    
    }
    
    0 讨论(0)
  • 2020-12-19 05:37

    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>
    
    0 讨论(0)
  • 2020-12-19 05:51

    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} />
    
    0 讨论(0)
提交回复
热议问题