Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is possible to make a WPF RelativeSource binding with AncestorType pointing to a base type?

I want to bind a property to the parent container view having a ViewModel in its DataContext.

This code works perfectly well when the parent is a direct instance of ConcreteClassView:

Property="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ty:ConcreteClassView}}, Path=DataContext.Name}"

However, the parent is not found when trying to locate it via a base class or a interface. Sample:

PropertyB="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ty:BaseClassView}}, Path=DataContext.Name}"

PropertyB="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ty:INamedElementView}}, Path=DataContext.Name}"

Giving that:

class ConcreteClassView : BaseClassView, INamedElementView { }

Ok, Let's assume that FindAncestor, AncestorType needs the concrete type to work.

But there is any workaround to locate ancestors just based on base classes or implementing a given Interface?

Thxs.

like image 828
pjmolina Avatar asked Nov 02 '12 11:11

pjmolina


1 Answers

FindAncestor, AncestorType do work with base classes, so your assumption is wrong.

Here is proof: This works

<HeaderedContentControl Tag="ABC">
    <TextBlock Text="{Binding Tag, RelativeSource={RelativeSource AncestorType=ContentControl}}" />
</HeaderedContentControl>

It works also with interface (Button implements ICommandSource):

<Button Tag="ABC">
    <TextBlock Text="{Binding Tag, RelativeSource={RelativeSource AncestorType=ICommandSource}}" />
</Button>

(Tested in .NET 4.5)

So why your code does not work?

  1. There may be another element derived from ty:BaseClassView in your visual tree between the binding target and the element you are looking for.

This doesn't work:

<HeaderedContentControl Tag="ABC">
    <Label>
        <TextBlock Text="{Binding Tag, RelativeSource={RelativeSource AncestorType=ContentControl}}" />
    </Label>
</HeaderedContentControl>

Label is also inherited from ContentControl, so Binding Source is Label in this case

  1. Visual Tree may be disconnected. For example Popup control is part of Logical Tree, but it has its own visual tree, so you can't use RelativeSource FindAncestor inside popup to look for parents outside popup. Please note, that elements are removed from visual tree also when you set Visibility="Collapsed"

How to debug?

  1. You can use converter to debug your binding. Just specify RelativeSource and some fake converter and leave the path empty. You can then place breakpoint to your converter, where value is be your binding source.

  2. Use loaded event of your element with binding to write all visual parents to Debug window

EDIT: Now in Visual Studio 2015, you can use Live Visual Tree explorer, to inspect the visual tree at runtime, (similarly like Browsers' developers tools can inspect dom elements). Using this tool you should be able to find bug in your application within few seconds.

https://msdn.microsoft.com/en-us/library/mt270227.aspx

like image 162
Liero Avatar answered Sep 23 '22 22:09

Liero