Posted 10 years ago by Billy Jacobs
Version: 4.5.0485
Platform: .NET 3.5
Environment: Windows Vista (32-bit)
Avatar
RelativeSource with FindAncestor does not work correctly for controls nested inside of a Popup button control:

If I do not nest my control inside of the Popup button control I get no error and it works correctly. When placing my control inside of a popup button control I get the following error:
System.Windows.Data Error: 4 : Cannot find source for binding with reference 'RelativeSource FindAncestor, AncestorType='StevenDale.PediNotes.Client.TestWindow', AncestorLevel='1''. BindingExpression:Path=DataContext.LabelText; DataItem=null; target element is 'Label' (Name='label1'); target property is 'Content' (type 'Object')

Here is the XAML for a small test case I wrote to reproduce the problem. I have a label that is not nested inside of the popup button and another label that is nested inside of a popup button. The one outside works. The one inside does not.
<Window x:Class="StevenDale.PediNotes.Client.TestWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:control="clr-namespace:StevenDale.PediNotes.Client.Controls"
    xmlns:uc="clr-namespace:StevenDale.PediNotes.Client.UserControls"
    xmlns:local="clr-namespace:StevenDale.PediNotes.Client"
    Title="TestWindow" xmlns:my="clr-namespace:ActiproSoftware.Windows.Controls;assembly=ActiproSoftware.Shared.Wpf30">
   
    
    <StackPanel>
        
        <Label Name="label2" Content="{Binding Path=DataContext.LabelText, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:TestWindow}}}"  DataContext="{Binding Path=DataContext, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:TestWindow}}}" />
        <my:PopupButton  Name="popupButton1">
            <my:PopupButton.PopupContent>
                <Label Name="label1" Content="{Binding Path=DataContext.LabelText, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:TestWindow}}}" />        
            </my:PopupButton.PopupContent>
        </my:PopupButton>
        
    </StackPanel>
</Window>
Here is the code behind.
    public partial class TestWindow : Window
    {
        private class TestObject2
        {
            public string LabelText { get; set; }
        }
        public TestWindow()
        {
            this.DataContext = new TestObject2 { LabelText = "Test Label Text" };
            InitializeComponent();            
        }
    }
Thanks In Advance,

Billy Jacobs

Comments (2)

Posted 10 years ago by Actipro Software Support - Cleveland, OH, USA
Avatar
Hi Billy,

Before I answer your specific question, I'd recommend that you use our namespace aliases (versus an explicit namespace). So instead of:
xmlns:my="clr-namespace:ActiproSoftware.Windows.Controls;assembly=ActiproSoftware.Shared.Wpf30"
use this:
xmlns:shared="http://schemas.actiprosoftware.com/winfx/xaml/shared"
This allows you to leverage all the classes and components in our Shared Library using "shared:", which would require several explicit namespace definitions. All of our controls have a namespace alias defined (e.g. ribbon, docking, propgrid, etc.).

As for your question, there are a couple issues with your code. First, the DataContext property is almost always inherited down the logical tree. Since you set the DataContext on your Window, the Label and PopupButton can directly, and implicitly, access it.

Second, the popup content is presented using a ContentPresenter. So ultimately the PopupContent becomes the "new" DataContext for the items in the popup. What you can do is bind the PopupContent to the inherited DataContext to pass it down, and then define your controls in the PopupContentTemplate (which defines how the content should be displayed).

The following code should accomplish what you are trying to do:
<StackPanel>
    <Label Name="label2" Content="{Binding LabelText}" />
    <shared:PopupButton Name="popupButton1" PopupContent="{Binding}">
        <shared:PopupButton.PopupContentTemplate>
            <DataTemplate>
                <Label Name="label1" Content="{Binding Path=LabelText}" />
            </DataTemplate>
        </shared:PopupButton.PopupContentTemplate>
    </shared:PopupButton>
</StackPanel>


Actipro Software Support

Posted 10 years ago by Billy Jacobs
Avatar
Your answer solved my problem.

Thank you very much.
The latest build of this product (v2019.1 build 0681) was released 1 month ago, which was after the last post in this thread.

Add Comment

Please log in to a validated account to post comments.