Обязательный конвертер как внутренний класс? - PullRequest
8 голосов
/ 14 мая 2009

У меня есть UserControl, который использует конвертер привязок. Я сделал конвертер внутренним классом

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

Как мне сослаться на класс Converter из XAML? Следующее не работает:

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

выдает эту ошибку:

тег 'LensPanel.CornerRadiusConverter' делает не существует в пространстве имен XML 'CLR-имен: MyApp.Windows.Controls'

Ответы [ 3 ]

2 голосов
/ 15 мая 2009

Я снова думал об этой проблеме и придумал что-то похожее на решение Денниса: создайте класс преобразователя «прокси» со свойством Type, которое будет создавать экземпляр фактического преобразователя и делегировать ему преобразование. .

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
}

Вы используете это так:

<Window.Resources>
    <my:Converter x:Key="CornerRadiusConverter" Type="{x:Type controls:MyPanel+CornerRadiusConverter}"/>
</Window.Resources>
2 голосов
/ 15 мая 2009

Это может быть возможно. Несколько месяцев назад я написал расширение для разметки, чтобы создать конвертер для вас. Он содержит словарь слабых ссылок, поэтому вы не можете создавать несколько экземпляров одного и того же конвертера. Также обрабатывает конвертеры с разными аргументами.

В 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 голосов
/ 15 мая 2009

Что я делаю, это:

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

А потом в контроле

  <CheckBox IsChecked="{Binding Path=BoolProperty, Converter={StaticResource BooleanNotConverter} />
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...