自定义MarkupExtension中的BindingExpressionBase为null

时间:2017-05-22 06:40:20

标签: c# wpf binding markup-extensions

我有一个CustomMarkupExtension课程。 Binding正在运行(!= null),但BindingExpressionBase始终是null

有人可以解释我为什么吗?我需要让BindingExpressionBase调用UpdateTarget()方法。

C#代码

public class CustomMarkupExtension : MarkupExtension
{

    public BindingBase Binding { get; set; }

    public override object ProvideValue(IServiceProvider serviceProvider)
    {
        if (Binding == null) return null;

        BindingExpressionBase expression = Binding.ProvideValue(serviceProvider) as BindingExpressionBase;
        if (expression != null)
        {
            expression.UpdateTarget();
        }
        return expression;
    }
}

XAML代码

<DataGrid ItemsSource="{Binding Path=Alarms, RelativeSource={RelativeSource TemplatedParent}}">
<DataGrid.Columns>
    <DataGridTemplateColumn>
        <DataGridTemplateColumn.CellTemplate>
            <DataTemplate>
                <TextBlock Text="{Extensions:CustomMarkupExtension Binding={Binding Number}}"/>
            </DataTemplate>
        </DataGridTemplateColumn.CellTemplate>
    </DataGridTemplateColumn>
</DataGrid.Columns>

1 个答案:

答案 0 :(得分:1)

原因是您在模板中使用了标记扩展(在本例中为DataTemplate)。当您的标记扩展由xaml解析器解析时 - 尚未创建控件,并且没有绑定目标。在这种情况下,您应该返回自己的标记扩展(return this)。如果你这样做 - 每次使用该模板创建控件时都会再次应用它。

内置Binding当然也遵循这种模式,这就是当目标对象尚不可用时它返回自身(Binding)而不是BindingExpression的原因。所以要修复,你必须这样做:

public class CustomMarkupExtension : MarkupExtension
{

    public BindingBase Binding { get; set; }

    public override object ProvideValue(IServiceProvider serviceProvider) {
        if (Binding == null) return null;

        var result = Binding.ProvideValue(serviceProvider);
        var expression = result as BindingExpressionBase;
        if (expression != null) {
            expression.UpdateTarget();
            return expression;
        }
        // no expression - return self to apply it again later
        return this;            
    }
}

如果您要创建不依赖于其他扩展的自定义标记扩展(在本例中为Binding),您可以通过执行此操作来检查您是否有目标:

var target = (IProvideValueTarget)serviceProvider.GetService(typeof(IProvideValueTarget));
bool hasTarget = target.TargetObject is DependencyObject;