Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

DependencyObject cannot find governing FrameworkElement for target element, even when that object is in the Logical Tree of a FrameworkElement

Tags:

c#

.net

wpf

After researching a bit on the Cannot find governing FrameworkElement or FrameworkContentElement for target element error, I found out dependency objects cannot really have bindable dependency properties unless they are FrameworkElements or are in the element tree of one.

However, I have a FrameworkElement which owns DependencyObjects, and I cannot send bindings to those DependencyObjects properties even though they are part of the FrameworkElement logical tree.

I'm writing a complex custom control with sub elements, and I need those sub elements to be DependencyObjects (but not FrameworkElements, because they get polluted with lots of properties which don't get used, and it could confuse users), and I also need their DependencyProperties to be bindable.

What am I missing? Is there anything else I need to tell the DependencyObjects so they're aware they are in a Logical Tree? Should I just make them Freezables even if it makes no sense for them to be frozen?

Cheers

like image 506
Abel Toy Avatar asked Apr 14 '16 11:04

Abel Toy


1 Answers

I think you conclusions & inferences are not entirely correct.

First thing is in WPF everything is derived from DependencyObject. FrameworkElement Class is not any different. If you look at the hierarchy of the FrameworkElement classs It's like below Order:

DependencyObject --> Visual --> UIElement -- > FrameworkElement

So if you try to create a Dependency Property in a class that is derived from any of the above classes, it will work just fine(excluding direct Binding but the Other way Binding Works(see example below)). There must be a problem with your CustomControl (Not sure you are using a CustomControl or UserControl) code .

But classes derived from UIElement can also have DependencyProperties that can be bound to other elements.

see UIElement class, It has lot of DependencyProperties.

UIElement

Please share the code of your control, we can look into that.

UPDATE:

Here is an example how a DependecyObject's DependencyProperty can be bound:

DependencyObject Implementation:

public class MyClass : DependencyObject
{
    public MyClass()
    {
        this.Button = new Button();
        Button.Width = 500;
        Button.Height = 400;
        Button.Content = "Bound to Window Height";
    }

    private Binding height;
    public Binding Height
    {
        get { return height; }
        set 
        {
            height = value;
            ApplyBinding();
        }
    }

    public Button Button { get; set; }
    private void ApplyBinding()
    {
        this.Button.SetBinding(Button.HeightProperty, this.Height);
    }

}

A UserControl Which uses Our DependencyObject Implementation:

public partial class MyUserControl : UserControl
{
    public MyUserControl()
    {
        InitializeComponent();
    }

    public MyClass MyClass
    {
        get { return (MyClass)GetValue(MyClassProperty); }
        set { SetValue(MyClassProperty, value); }
    }

    // Using a DependencyProperty as the backing store for MyClass.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty MyClassProperty =
        DependencyProperty.Register("MyClass", typeof(MyClass), typeof(MyUserControl), new UIPropertyMetadata(new PropertyChangedCallback(MyClassPropertyChanged)));


    private static void MyClassPropertyChanged(DependencyObject DO, DependencyPropertyChangedEventArgs e)
    {
        var MUC = DO as MyUserControl;
        if (e.NewValue != null)
        {
            var myClass = e.NewValue as MyClass;                
            MUC.MyCanvas.Children.Add(myClass.Button);
        }
    }

}

And Finally Binding:

<Window x:Class="WpfStackOverflowTempProject.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow"  Width="525"
    DataContext="{Binding RelativeSource={RelativeSource Mode=Self}}"
    xmlns:local="clr-namespace:WpfStackOverflowTempProject"     
    Height="{Binding ElementName=UIContent,Path=MyClass.HeightReplica,Mode=OneWayToSource}"
    >
<local:MyUserControl x:Name="UIContent" >
    <local:MyUserControl.MyClass>
        <local:MyClass Height="{Binding RelativeSource={RelativeSource AncestorType=Window},Path=ActualHeight,Mode=OneWay}" />
    </local:MyUserControl.MyClass>
</local:MyUserControl>

So as output of above program when Height of our Window changes, it will reflected back to our MyClass component's Button element like we have done binding to Button itself in XAML code. So the Myclass is a interface between it's logical parent control & it's children elements for specifying the exposed properties/bindings and defining the behave of them corresponding to the child elements, which actually will be visible on the UI and MyClass will work only like a filter for idiomatic uses.

like image 149
Kylo Ren Avatar answered Nov 15 '22 00:11

Kylo Ren