RelativeSource not working using child property

589 Views Asked by At

I do not understand the issue / difference with the first binding with these examples:

(CustomTheme, ItemFormatting and FontNormal are DependencyObjects)

This one gets the error further down:

          NullToDependencyPropertyUnsetConverter unsetconv = new NullToDependencyPropertyUnsetConverter();

            Binding binding = new Binding("CustomTheme.ItemFormatting.FontNormal")
            {
                Converter = unsetconv,
                RelativeSource = new RelativeSource(RelativeSourceMode.FindAncestor, typeof(ThemableUserControl), 2)
            };
            BindingOperations.SetBinding(itemsample.ItemFormatting, ItemFormatting.FontNormalProperty, binding);

This is an absolute equivalent of the first one and works:

     Binding binding = new Binding("CustomTheme.ItemFormatting.FontNormal")
            {
                Converter = unsetconv,
                Source = tucMain
            };
            BindingOperations.SetBinding(itemsample.ItemFormatting, ItemFormatting.FontNormalProperty, binding);

This is not what I want to achieve but works:

            Binding binding1 = new Binding("CustomTheme.ItemFormatting")
            {
                Converter = unsetconv,
                RelativeSource = new RelativeSource(RelativeSourceMode.FindAncestor, typeof(ThemableUserControl), 2)
            };
            BindingOperations.SetBinding(itemsample, uc_item.ItemFormattingProperty, binding1);

I do not understand why I am getting the this output error on the first one:

System.Windows.Data Error: 4 : Cannot find source for binding with reference 'RelativeSource FindAncestor, AncestorType='AddonInterface.ThemableUserControl', AncestorLevel='2''. BindingExpression:Path=CustomTheme.ItemFormatting.FontNormal; DataItem=null; target element is 'ItemFormatting' (HashCode=43532274); target property is 'FontNormal' (type 'Font')

This is the window xaml.

<Window
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:TestApp"
        xmlns:UIControls="clr-namespace:AddonInterface.UIControls;assembly=AddonInterface" xmlns:AddonInterface="clr-namespace:AddonInterface;assembly=AddonInterface"
    xmlns:uielements="clr-namespace:AddonInterface.UIElements;assembly=AddonInterface"
    xmlns:c="clr-namespace:CalcBinding;assembly=CalcBinding" x:Class="TestApp.SubthemeWidgetItem"
        mc:Ignorable="d" x:Name="this"
        Title="MainWindow" Height="579.722" Width="1040.889" Loaded="This_Loaded" 
    DataContext="{Binding RelativeSource={RelativeSource Self}}"
    
    >
    <Window.Resources>
        <ResourceDictionary Source="pack://application:,,,/AddonInterface;component/Themes/defaultMainStyle.xaml"/>

    </Window.Resources>

    <AddonInterface:ThemableUserControl Name="tucMain" >
        <StackPanel>
            <AddonInterface:ThemableUserControl Name="tucSub" Height="225" Margin="0,0,604,0">
                <DockPanel Margin="0,0,-18,-41">


                    <Label Height="33">x) tuc2</Label>
                    <AddonInterface:AddonUserControl Name="aucSub" Margin="0,0,0,155" Width="147">
                        <DockPanel>
                            <Label Height="33">x) auc</Label>

                            <AddonInterface:uc_item  Name="itemsample" Title="x) item " />
                        </DockPanel>


                    </AddonInterface:AddonUserControl>


                </DockPanel>

            </AddonInterface:ThemableUserControl>


            <CheckBox IsChecked="True" Name="cbx2" FontSize="20" FontWeight="Bold">Toptheme</CheckBox>
            <UIControls:uc_themedesigner Visibility="{c:Binding ElementName=cbx2,Path=IsChecked}"  Name="mainwindowtheme"   />
            <CheckBox IsChecked="True" Name="cbx1" FontSize="20" FontWeight="Bold">Subtheme</CheckBox>
            <UIControls:uc_themedesigner Visibility="{c:Binding ElementName=cbx1,Path=IsChecked}" AllowNulls="True" Name="customtheme"    ></UIControls:uc_themedesigner>
            <Button Content="Button" Click="Button_Click_1"/>





        </StackPanel>

    </AddonInterface:ThemableUserControl>



</Window>

Code behind:

using AddonInterface;
using AddonInterface.DependencyObjects;
using AddonInterface.themes;
using AddonInterface.UIControls;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace TestApp
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class SubthemeWidgetItem : Window
    {
        public SubthemeWidgetItem()
        {



            InitializeComponent();

            tucMain.CustomTheme = new dm_theme();
            tucMain.CustomTheme.ApplyAllDefault();
            tucMain.CustomTheme.ItemFormatting.FontNormal = new Font() { Size=60}; 
            tucSub.CustomTheme = new dm_theme();



            //BINDINGS THEME DESIGNER / TUC THEME
            mainwindowtheme.SetBinding(uc_themedesigner.ThemeDMProperty, new Binding("CustomTheme") { Source = tucMain });
            customtheme.SetBinding(uc_themedesigner.ThemeDMProperty, new Binding("CustomTheme") { Source = aucSub });


        

            this.Loaded += (a, b) =>
            {




                NullToDependencyPropertyUnsetConverter unsetconv = new NullToDependencyPropertyUnsetConverter();

                //Binding binding = new Binding("CustomTheme.ItemFormatting.FontNormal")
                //{
                //    Converter = unsetconv,
                //    RelativeSource = new RelativeSource(RelativeSourceMode.FindAncestor, typeof(ThemableUserControl), 2)
                //};
                //BindingOperations.SetBinding(itemsample.ItemFormatting, ItemFormatting.FontNormalProperty, binding);



                Binding binding = new Binding("CustomTheme.ItemFormatting.FontNormal")
                {
                    Converter = unsetconv,
                    Source = tucMain
                };
                BindingOperations.SetBinding(itemsample.ItemFormatting, ItemFormatting.FontNormalProperty, binding);



                //Binding binding1 = new Binding("CustomTheme.ItemFormatting")
                //{
                //    Converter = unsetconv,
                //    RelativeSource = new RelativeSource(RelativeSourceMode.FindAncestor, typeof(ThemableUserControl), 2)
                //};
                //BindingOperations.SetBinding(itemsample, uc_item.ItemFormattingProperty, binding1);




            };

            TestBorder = new dm_border() { Background = Brushes.Orange };

            this.DataContext = this;
        }





        public dm_border TestBorder
        {
            get { return (dm_border)GetValue(TestBorderProperty); }
            set
            {
                SetValue(TestBorderProperty, value);


            }
        }


        public static readonly DependencyProperty TestBorderProperty =
         DependencyProperty.Register("TestBorder", typeof(dm_border), typeof(SubthemeWidgetItem),
     new FrameworkPropertyMetadata(default(dm_border),
         FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
         new PropertyChangedCallback(OnTestBorderPropertyChanged)));


        private static void OnTestBorderPropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {
            SubthemeWidgetItem uci = sender as SubthemeWidgetItem;
            if (uci != null)
            {
                uci.OnTestBorderChanged();
            }
        }


        private void OnTestBorderChanged()
        {


        }




    }
}

thanks Have a nice day

2

There are 2 best solutions below

2
On

The first binding is wrong, as the target object is itemSample. itemsample.ItemFormatting is a property on itemSample and not an element of the visual tree. That's why RelativeSource can't be resolved by the XAML parser.

To make the RelativeSource binding using the same source as your second code version, you must change the Binding.Path.

Note that setting a binding on a nested property is not possible using BindingOperations. The binding must be set directly on the object that owns the target property. You can use FrameworkElement.SetBinding for this purpose.

The final binding would become:

C#

var unsetConv = new NullToDependencyPropertyUnsetConverter();

var binding = new Binding("CustomTheme.ItemFormatting.FontNormal")
{
  Converter = unsetConv,
  RelativeSource = new RelativeSource(RelativeSourceMode.FindAncestor, typeof(ThemableUserControl), 2)
};

itemSample.ItemFormatting.SetBinding(ItemFormatting.FontNormalProperty, binding);

XAML

<Window.Resources>
  <NullToDependencyPropertyUnsetConverter x:Key="NullToDependencyPropertyUnsetConverter" />
</Window.Resources>

<AddonInterface:uc_item  Name="ItemSample" 
                         ItemFormatting="{Binding RelativeSource={RelativeSource AncestorType=ThemableUserControl, AncestorLevel=2}, 
                                                  Path=CustomTheme.ItemFormatting, 
                                                  Converter={StaticResource NullToDependencyPropertyUnsetConverter}}" />

Since you are using a named element as the binding source, you can also use the Binding.ElementName property instead:

<AddonInterface:uc_item  Name="ItemSample" 
                         ItemFormatting="{Binding Elementname=tucMain, 
                                                  Path=CustomTheme.ItemFormatting, 
                                                  Converter={StaticResource NullToDependencyPropertyUnsetConverter}}" />
0
On

I have ended up using an extension method getParent<> to find the themableusercontrol ancestor and setting it as source.