【问题标题】:Collection-Type Attached Properties集合类型附加属性
【发布时间】:2018-05-08 08:08:21
【问题描述】:

我想通过收集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);

}

【问题讨论】:

    标签: c# binding uwp dependency-properties attached-properties


    【解决方案1】:

    在 WPF 中,可以通过使用 FreezableCollection&lt;T&gt; 或从 Freezable 类、IList&lt;T&gt;IList 继承:

    1. DependencyObject 继承它,因为无法访问DependencyObject 的两个必需方法,但Freezable 有一个包装器。
    2. 根据需要实现 IList&lt;T&gt;IList
    3. 向集合中添加新元素时调用OnFreezablePropertyChanged(null, newItem)
    4. 从其中删除元素时,调用OnFreezablePropertyChanged(item, null)

    OnFreezablePropertyChanged 方法内部会调用DependencyObject 的两个方法来提供或移除继承上下文(source)。

    但是在 UWP 中没有 Freezable 并且没有这样的方法,所以在 Windows 10.0.10240.0 之前是不可能的。但是,如果您的目标是 v10.0.10240.0 或更高版本,则应使用为行为而设计的DependencyObjectCollection

    DependencyObjectCollection 类的目的主要是支持行为的工具化和可移植性。行为是一种完全在 XAML 中定义 UI 元素的某些基本交互的技术,不需要事件处理程序和代码隐藏。

    因此,在 UWP 和 WPF 中,只有当子级是逻辑/可视子级或依赖属性值时,才能将继承上下文提供给子级。因此,Binding 与 set ElementName 在您的情况下使用时不起作用。 ElementName 属性用于在绑定附加到依赖对象而不是编译时在运行时解析对象。

    UWP 绑定的工作方式与 WPF 绑定类似,因此请参见第二个平台的 ElementObjectRef.GetObject

    【讨论】:

    • DependencyObjectCollection 与其事件处理程序 VectorChangedEventHandler 结合使用效果很好。谢谢你。如果不是很费力,请您也回答其他问题,因为我想知道解决绑定时后台发生了什么。
    • @Chris 是的,当然。我打算扩大答案,但在我的业余时间(:
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-20
    相关资源
    最近更新 更多