Dominic Jonas Dominic Jonas -4 years ago 67
C# Question

BindingExpressionBase is null in custom MarkupExtension

I have a

CustomMarkupExtension
class. The Binding is working (!= null), but the
BindingExpressionBase
is always
null
.

Can someone explain me why? I need to get the
BindingExpressionBase
to call the
UpdateTarget()
method.

C# Code



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 Code



<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>



Answer Source

The reason for that is you are using markup extension inside a template (DataTemplate in this case). When your markup extension is parsed by xaml parser - control is not yet created and there is no target for a binding. In such case you should return your markup extension itself (return this). If you do it - it will be applied again each time control is created using that template.

Built-in Binding is of course follows this pattern too, that is why it returns itself (Binding) and not BindingExpression when target object is not yet available. So to fix, you have to do this:

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;            
    }
}

If you will create custom markup extension which does not rely on other extension (like Binding in this case), you can check if you have target by doing this:

var target = (IProvideValueTarget)serviceProvider.GetService(typeof(IProvideValueTarget));
bool hasTarget = target.TargetObject is DependencyObject;
Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download