如何解析 MarkupExtension 中数据绑定的值? [英] How do I resolve the value of a databinding inside a MarkupExtension?
问题描述
我制作了一个标记扩展,用于基于键翻译字符串.示例
I've made a markup extension for translating strings based on a key. Example
<TextBlock Text="{Translate myKey}" />
现在我希望能够使用嵌套绑定来提供我的密钥.示例:
Now I want to be able to use nested bindings for providing my keys. Example:
<TextBlock Text="{Translate {Binding KeyFromDataContext}}" />
当我这样做时,我得到一个 System.Windows.Data.Binding 对象.通过调用 ProvideValue 并传递 ServiceProvider,我可以获得 BindingExpression:
When I do this I get a System.Windows.Data.Binding object. By calling ProvideValue and passing down the ServiceProvider I can get a 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 属性为空.我已经像这样测试了我的绑定
I can get this bindingExpression, but the DataItem property is null. I've tested my binding like this
<TextBlock Text="{Binding KeyFromDataContext}" />
它工作正常.
有什么想法吗?
推荐答案
toxvaerd 的答案 并不普遍.如果原始绑定已经有一个转换器,它就会中断.或者当无法编写转换器时.
The toxvaerd's answer is not universal. It breaks if the original binding already had a converter. Or when writing a converter is not possible.
有一个更好的解决方案.我们可以声明两个构造函数.当使用绑定时,XAML 将调用第二个接受 BindingBase
的方法.为了解析绑定的值,我们可以声明一个私有附加属性.为此,我们需要知道标记扩展的目标元素.
There's a better solution. We can declare two constructors. The second one accepting BindingBase
will be called by XAML when a binding is used. To resolve the value of the binding, we can declare a private attached property. For this to work we need to know the target element of the markup extension.
有一个问题:当在模板中使用标记扩展时,没有目标元素(显然).在这种情况下,您是 应该在ProvideValue()中使用
return this
- 这样在应用模板时会再次调用扩展.
There's a catch: when the markup extension is used inside a template, there is no target element (obviously). In this case you are supposed to use return this
in ProvideValue()
- this way the extension will be called again when the template is applied.
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));
}
这篇关于如何解析 MarkupExtension 中数据绑定的值?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!