我已经为基于密钥翻译字符串做了标记扩展。实施例
<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属性为null。我已经像这样测试了我的装订
<TextBlock Text="{Binding KeyFromDataContext}" />
它工作正常。
有什么想法吗?
答案 0 :(得分:2)
不可以获得绑定的值。你不应该尝试这样做。 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解析并作为值传递给转换器,而一个简单的文本键作为参数传递给转换器。
从ServiceProvider获取 _targetObject
和_targetProperty
。
答案 1 :(得分:0)
toxvaerd's answer不是普遍的。如果原始绑定已经有转换器,它会中断。或者当无法编写转换器时。
有一个更好的解决方案。我们可以声明两个构造函数。当使用绑定时,XAML将调用接受BindingBase
的第二个。要解析绑定的值,我们可以声明一个私有附加属性。为此,我们需要知道标记扩展的目标元素。
有一个问题:当在模板中使用标记扩展时,没有目标元素(显然)。在这种情况下,return this
supposed 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));
}
- 这样在应用模板时将再次调用扩展名。
android:inputType="number|numberDecimal"