I would like to extend FrameworkElement
elements like the Button
class by collection-type attached property that collect DependencyObjects
.
The difficulty is that the bindings to the collection items do not work: No debug nor runtime error shows up but the bound source gets never called.
I noted that the collection-type attached property does not inherit from class DependencyObject
.
I guess the DataContext
property will be inherited by any child DependencyObject
object (as long as the parent is also a DependencyObject
object). As the collection-type attached property does not inherit from DependencyObject
the DataContext
property inheritance does not occur.
DependencyObject
can inherit the DataContext
property as DataContext
is a property defined in FrameworkElement
? How does the DependencyObject
manage the DataContext
lookup?ElementName=PageName
not work as well (e.g. {Binding MyProperty="{Binding DataContext.PropertySource1, ElementName=PageName}
)? If the DependencyObject
is also responsible for ElementName
lookups, how does it do it?DependencyObject
? (In WPF there is FreezableCollection<T>
class but I couldn't find a pendant in the UWP environment.)The XAML markup below shows an example extension, where the Binding
does not work.
<Button Name="Button">
<ext:MyExtension.MyCollection>
<ext:MyDependencyObject MyProperty="{Binding PropertySource1}"/>
<ext:MyDependencyObject MyProperty="{Binding PropertySource1}"/>
</ext:MyExtension.MyCollection>
</Button>
If I do the following extension for non-collection-type attached properties the binding can be resolved correctly.
<Button Name="Button">
<ext:MyExtension.MyProperty>
<ext:MyDependencyObject MyProperty="{Binding PropertySource1}"/>
</ext:MyExtension.MyProperty>
</Button>
The code below shows a sample collection-type attached property implementation. Consider the attached property class also contains a definition for a non-colleciton-type attached property (which works correctly with binding).
public class MyDependencyObject: DependencyObject
{
public object MyProperty
{
get { return (object)GetValue(MyPropertyProperty ); }
set { SetValue(MyPropertyProperty , value); }
}
public static readonly DependencyProperty MyPropertyProperty =
DependencyProperty.Register("MyProperty", typeof(object), typeof(MyProperty), null);
}
public class MyPropertyCollection : ObservableCollection<MyDependencyObject> { }
public static class MyExtension
{
// Collection-type AttachedProperty with DependencyObject items
public static MyPropertyCollection GetMyPropertyCollection(DependencyObject obj)
{
MyPropertyCollection collection = (MyPropertyCollection )obj.GetValue(MyCollectionProperty );
if (collection == null)
{
collection = new MyPropertyCollection();
collection.CollectionChanged +=
(sender, e) =>
{
//intiailization of elements possible
};
obj.SetValue(MappingsProperty, collection);
}
return collection;
}
public static void SetMyPropertyCollection(DependencyObject obj, MyPropertyCollection value)
{
obj.SetValue(MyCollectionProperty , value);
}
public static readonly DependencyProperty MyCollectionProperty =
DependencyProperty.RegisterAttached("MyCollection", typeof(MyPropertyCollection), typeof(MyExtension), null);
// DependencyObject-type AttachedProperty
public static MyProperty GetMapping(DependencyObject obj)
{
return (MyProperty )obj.GetValue(MyPropertyProperty );
}
public static void SetMapping(DependencyObject obj, MyProperty value)
{
obj.SetValue(MyPropertyProperty , value);
}
public static readonly DependencyProperty MyPropertyProperty =
DependencyProperty.RegisterAttached("MyProperty", typeof(MyDependencyObject), typeof(MyExtension), null);
}
In WPF it's possible via using FreezableCollection<T>
or via inheriting from the Freezable
class, IList<T>
and IList
:
DependencyObject
because there are no way to access two required methods of the DependencyObject
, but Freezable
has a wrapper around them.IList<T>
and IList
as you want.OnFreezablePropertyChanged(null, newItem)
.OnFreezablePropertyChanged(item, null)
.The OnFreezablePropertyChanged
method internally will call two methods of DependencyObject
to provide or remove the inheritance context (source).
But in UWP there is no Freezable
and there are no such methods, so until Windows 10.0.10240.0 it isn't possible. But if you are targeting v10.0.10240.0 or later you should use DependencyObjectCollection
which is made for behaviors.
The purpose of the DependencyObjectCollection class is mainly to support the tooling and portability of behaviors. Behaviors are a technique for defining certain basic interactions of a UI element entirely in XAML, without requiring an event handler and code-behind.
So in UWP and WPF the inheritance context can be provided to children only if they are logical/visual children or they are dependency property values. And because of that the Binding
with set ElementName
doesn't work when it is used in your case. The ElementName
property is used to resolve an object at runtime when the binding is attached to the dependency object and not at compile time.
UWP bindings work like WPF bindings so for example see ElementObjectRef.GetObject
from the second platform.