代码之家  ›  专栏  ›  技术社区  ›  toxvaerd

如何解析MarkupExtension中数据绑定的值?

  •  5
  • toxvaerd  · 技术社区  · 15 年前

    我做了一个标记扩展来翻译基于键的字符串。例子

    <TextBlock Text="{Translate myKey}" />
    

    现在,我希望能够使用嵌套绑定来提供我的键。例子:

    <TextBlock Text="{Translate {Binding KeyFromDataContext}}" />
    

    当我这样做时,会得到一个System.Windows.Data.Binding对象。通过调用ProvideValue并传递ServiceProvider,我可以获得一个bindingExpression:

    var binding = Key as Binding;
    if (binding == null) {
        return null;
    }
    var bindingExpression = binding.ProvideValue(_serviceProvider) as BindingExpression;
    if (bindingExpression == null) {
        return null;
    }
    var bindingKey = bindingExpression.DataItem;
    

    我可以获取此bindingExpression,但dataItem属性为空。我像这样测试过我的装订

    <TextBlock Text="{Binding KeyFromDataContext}" />
    

    而且效果很好。

    有什么想法吗?

    2 回复  |  直到 7 年前
        1
  •  0
  •   torvin Mayank    7 年前

    这个 toxvaerd's answer 不是万能的。如果原始绑定已经有转换器,则它将中断。或者写转换器是不可能的。

    有更好的解决方案。我们可以声明两个构造函数。第二个接受 BindingBase 将在使用绑定时由XAML调用。为了解析绑定的值,我们可以声明私有的附加属性。为了实现这一点,我们需要知道标记扩展的目标元素。

    有一个陷阱:当在模板中使用标记扩展时,没有目标元素(显然)。在这种情况下,你是 supposed 使用 return this 在里面 ProvideValue() -这样,在应用模板时将再次调用扩展名。

    public class TranslateExtension : MarkupExtension
    {
        private readonly BindingBase _binding;
    
        public TranslateExtension(BindingBase binding)
        {
            _binding = binding;
        }
    
        public TranslateExtension(string key)
        {
            Key = key;
        }
    
        [ConstructorArgument("key")]
        public string Key { get; set; }
    
        public override object ProvideValue(IServiceProvider serviceProvider)
        {
            if (_binding != null)
            {
                var pvt = (IProvideValueTarget)serviceProvider.GetService(typeof(IProvideValueTarget));
                var target = pvt.TargetObject as DependencyObject;
    
                // if we are inside a template, WPF will call us again when it is applied
                if (target == null)
                    return this; 
    
                BindingOperations.SetBinding(target, ValueProperty, _binding);
                Key = (string)target.GetValue(ValueProperty);
                BindingOperations.ClearBinding(target, ValueProperty);
            }
    
            // now do the translation using Key
            return ...;
        }
    
        private static readonly DependencyProperty ValueProperty = 
            DependencyProperty.RegisterAttached("Value", typeof(string), typeof(TranslateExtension));
    }
    
        2
  •  2
  •   toxvaerd    15 年前

    它是 可以获取绑定的值。你甚至不应该这么做。WPF使用一些奇特的反射来解析绑定并相信我——您不希望自己开始尝试。

    总之,考虑到这一点,这就是我最终所做的,这实际上是一个很好的解决方案:

    我做了一个 TranslateConverter 负责翻译的:

    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        var key = value as string ?? parameter as string;
    
        if (key != null)
        {
        // Do translation based on the key
    
        }
        return null;
    }
    

    然后在我的 TranslateExtension 我只是这样做:

    var binding = Key as Binding ?? new Binding{Mode = BindingMode.OneWay};
    binding.Converter = new TranslateConverter(_targetObject, _targetProperty, Dictionary, Converter);
    binding.ConverterParameter = Key is Binding ? null : Key as string;
    
    return binding.ProvideValue(serviceProvider);
    

    通过这种方式,绑定由wpf解析并作为值传递给转换器,而简单的文本键作为参数传递给转换器。

    _targetObject _targetProperty 从服务提供程序获取。

    推荐文章