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
1 Answers
Answers 1
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.
0 comments:
Post a Comment