如何向自定义附加 属性 提供元素集合?

How do I provide a collection of elements to a custom attached property?

我在网上找到了一些例子,在这里找到了一些问题和答案,但我就是无法让它工作。我需要一个可以接受一个或多个目标元素的自定义附加 属性。例如...

<ListView>
    <dd:MyDragDrop.DropBorders>
        <Binding ElementName="brdOne"/>
        <Binding ElementName="brdTwo"/>
        <Binding ElementName="brdThree"/>
    </dd:MyDragDrop.DropBorders>
</ListView>

我也尝试过使用 MultiBinding,但没有成功。

<ListView>
    <dd:MyDragDrop.DropBorders>
        <MultiBinding Converter="{StaticResource multi}">
            <Binding ElementName="brdOne"/>
            <Binding ElementName="brdTwo"/>
            <Binding ElementName="brdThree"/>
        </MultiBinding>
    </dd:MyDragDrop.DropBorders>
</ListView>

稍后有时间我会详细说明,但与此同时.. 有 'correct' 方法吗?感觉应该比我做的简单!

仅供参考,这是我正在玩的附件 属性。现在完全是一个实验,所以根本没有润色,主要是尝试不同在线解决方案的不同解决方案的结果。

public class BorderCollection : List<Border>
{

}

public static readonly DependencyProperty DropBordersProperty = DependencyProperty.RegisterAttached("DropBorders", typeof(BorderCollection), typeof(MyDragDrop));

public static BorderCollection GetDropBorders(ListView listView)
{
    var collection = (BorderCollection)listView.GetValue(DropBordersProperty);
    if (collection == null)
    {
        collection = new BorderCollection();
        listView.SetValue(DropBordersProperty, collection);
    }
    return collection;
}

public static void SetDropBorders(ListView listView, BorderCollection borders)
{
    listView.SetValue(DropBordersProperty, borders);

    foreach (Border border in borders)
    {
        border.Background = new SolidColorBrush(Colors.Green);
    }
}

谢谢。

您的 BorderCollectionListBorder 个元素,但是,您正在尝试使用 Binding 个元素的集合。

<dd:MyDragDrop.DropBorders>
    <Binding ElementName="brdOne"/>
    <Binding ElementName="brdTwo"/>
    <Binding ElementName="brdThree"/>
</dd:MyDragDrop.DropBorders>

记住,Binding 个元素 不是 Border 个元素。您的 DropBorders 集合需要 Border 的列表。像这样:

<dd:MyDragDrop.DropBorders>
    <Border ... />

    ...
</dd:MyDragDrop.DropBorders>

考虑将您的 BorderCollection 改为继承 List<Binding>。然后,您可以使用您的绑定集合来获取集合中的边框。

您应该能够执行以下操作:

<ListView>
    <dd:MyDragDrop.DropBorders>
        <Border Style="{StaticResource brdOneStyle}"/>
        <Border Style="{StaticResource brdTwoStyle}"/>
        <Border Style="{StaticResource brdThreeStyle}"/>
    </dd:MyDragDrop.DropBorders>
</ListView>

我不建议您使用绑定指定 DropBorders,因为 Border 是 UIElement,而 UIElement 只能在可视化树中出现一次。如果您有多个列表视图使用相同的 Border 元素实例,则可能会出现运行时错误。如果您想重复使用边框,请改用样式。

我设法使用这样的 IMultiValueConverter 让它工作:

public class BorderCollectionConverter : IMultiValueConverter
{
    public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        var borderCollection = new BorderCollection();
        borderCollection.AddRange(values.OfType<Border>());

        return borderCollection;
    }

    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

并在 XAML 中使用它,就像在您的示例中一样:

    <Border Height="20" Name="border1" Background="Blue" />
    <Border Height="20" Name="border2" Background="Green" />
    <Border Height="20" Name="border3" Background="Yellow" />
    <Control>
        <dd:MyDragDrop.DropBorders>
            <MultiBinding Converter="{StaticResource borderCollectionConverter}">
                <Binding ElementName="border1" />
                <Binding ElementName="border3" />
            </MultiBinding>
        </dd:MyDragDrop.DropBorders>
    </Control>

主要区别在于我声明 DependencyProperty 的方式,使用问题评论中给出的建议(getter 或 setter 中没有代码,而是使用元数据定义一个 属性 改变的回调):

public static readonly DependencyProperty DropBordersProperty = 
    DependencyProperty.RegisterAttached("DropBorders", typeof(BorderCollection), typeof(MyDragDrop),
    new PropertyMetadata(null, DropBordersChanged));

public static BorderCollection GetDropBorders(DependencyObject listView)
{
    return (BorderCollection)listView.GetValue(DropBordersProperty);
}

public static void SetDropBorders(DependencyObject listView, BorderCollection borders)
{
    listView.SetValue(DropBordersProperty, borders);
}

public static void DropBordersChanged(object sender, DependencyPropertyChangedEventArgs e)
{
    foreach (var border in (BorderCollection)e.NewValue)
        border.Background = new SolidColorBrush(Colors.Red);
}

最后的结果...