Reputation: 328
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
Upvotes: 8
Views: 4234
Reputation: 8813
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 haveDependencyProperties
that can be bound to other elements.
see UIElement
class, It has lot of DependencyProperties
.
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 ourWindow
changes, it will reflected back to ourMyClass
component's Buttonelement
like we have done binding toButton
itself inXAML
code. So theMyclass
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 andMyClass
will work only like a filter for idiomatic uses.
Upvotes: 2