集合类型附加属性

pdolor 发布于 2019-11-08 binding 最后更新 2019-11-08 22:59 20 浏览

我想通过收集DependencyObjects的集合类型附加属性来扩展FrameworkElement元素,例如Button类。 难点在于对​​收集项目的绑定不起作用:没有调试或运行时错误出现,但绑定的源码永远不会被调用。 我注意到集合类型附加属性不会从类DependencyObject继承。 我猜DataContext属性会被任何子DependencyObject对象继承(只要父对象也是DependencyObject对象)。由于集合类型的附加属性不从DependencyObject继承,DataContext属性继承不会发生。

  1. 我想知道为什么DependencyObject的实例可以继承DataContext属性,因为DataContextFrameworkElement中定义的属性? DependencyObject如何管理DataContext查找?
  2. 为什么使用ElementName=PageName指定绑定来源不是很好(例如{Binding MyProperty="{Binding DataContext.PropertySource1, ElementName=PageName})?如果DependencyObject也负责ElementName查找,那么它是如何执行的?
  3. 是否有继承DependencyObject的UWP集合? (在WPF中有FreezableCollection<T>类,但我在UWP环境中找不到挂件。)
下面的XAML标记显示了一个示例扩展,其中Binding不起作用。
<Button Name="Button">
    <ext:MyExtension.MyCollection>
        <ext:MyDependencyObject MyProperty="{Binding PropertySource1}"/>
        <ext:MyDependencyObject MyProperty="{Binding PropertySource1}"/> 
    </ext:MyExtension.MyCollection>
</Button>
如果我为非集合类型的附加属性执行以下扩展,则可以正确解析绑定。
<Button Name="Button">
    <ext:MyExtension.MyProperty>
        <ext:MyDependencyObject MyProperty="{Binding PropertySource1}"/>
    </ext:MyExtension.MyProperty>
</Button>
下面的代码显示了一个示例集合类型的附加属性实现。考虑附加的属性类还包含非集合类型附加属性的定义(该属性可与绑定一起正确工作)。
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);
}
已邀请:

lqui

赞同来自:

在WPF中,可以通过FreezableCollection<T>或继承FreezableIList<T>IList来实现:

  1. DependencyObject继承它,因为无法访问DependencyObject的两个必需方法,但Freezable有一个包装器。
  2. 根据需要实施IList<T>IList
  3. 向集合中添加新元素时,请调用OnFreezablePropertyChanged(null, newItem)
  4. 从中移除元素时,请调用OnFreezablePropertyChanged(item, null)
OnFreezablePropertyChanged方法在内部将调用DependencyObject的两个方法来提供或删除继承上下文(source)。 但是在UWP中没有Freezable并且没有这样的方法,所以在Windows 10.0.10240.0之前它是不可能的。但是,如果您的目标是v10.0.10240.0或更高版本,则应使用针对行为制作的DependencyObjectCollection
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.
因此,在UWP和WPF中,只有当子节点是逻辑/可视子节点或它们是依赖属性值时,才能向子节点提供继承上下文。因此,设置ElementNameBinding在您的案例中使用时不起作用。当绑定附加到依赖项对象而不是编译时,ElementName属性用于在运行时解析对象。 UWP绑定的工作方式与WPF绑定类似,例如,请参阅第二个平台的ElementObjectRef.GetObject