简体   繁体   English

在WPF中将元素列表绑定到基于集合的依赖项属性

[英]Binding a list of elements to a collection-based dependency property in WPF

I'm implementing a custom Blend behavior in a WPF application (.Net 4.5). 我正在WPF应用程序(.Net 4.5)中实现自定义Blend行为。 I've added a couple of dependency properties of type FrameworkElement to the behavior class to allow the user of the behavior to bind the elements of the view that they want to control. 我在行为类中添加了一些类型为FrameworkElement的依赖项属性,以允许行为的用户绑定他们想要控制的视图的元素。 (This behavior invokes some animation on multiple elements, so I can't just use the AssociatedObject). (此行为会在多个元素上调用某些动画,因此我不能仅使用AssociatedObject)。 This works fine and basically looks like this: 这工作正常,基本上看起来像这样:

public class MyBehavior : Behavior<FrameworkElement>
{
    public static readonly DependencyProperty Element1Property = DependencyProperty.Register("Element1", typeof (FrameworkElement), typeof (MyBehavior), new UIPropertyMetadata());

    public FrameworkElement Element1
    {
        get { return (FrameworkElement) GetValue(Element1Property); }
        set { SetValue(Element1Property, value); }
    }

    public static readonly DependencyProperty Element2Property = DependencyProperty.Register("Element2", typeof(FrameworkElement), typeof(MyBehavior), new UIPropertyMetadata());

    public FrameworkElement Element2
    {
        get { return (FrameworkElement) GetValue(Element2Property); }
        set { SetValue(Element2Property, value); }
    }
}

Standard dependency property stuff. 标准依赖项属性的东西。 And I can use that in my view like this: 我可以这样使用它:

<Grid x:Name="Container">
    <i:Interaction:Behaviors>
        <local:MyBehavior
            Element1="{Binding ElementName=FirstElement}"
            Element2="{Binding ElementName=SecondElement}"
        />
    </i:Interaction:Behaviors>
</Grid>

This works great and I can work with the elements in the behavior. 这很好用,我可以处理行为中的元素。 But now I have a requirement to bind a list of elements like this. 但是现在我需要绑定这样的元素列表。 So I don't know ahead of time that there are going to be exactly 2 elements, there could be N elements that I need to work with. 所以我不提前知道会有2个元素,可能需要N个元素。 So I've added another property to the MyBehavior class like this: 因此,我向MyBehavior类添加了另一个属性,如下所示:

public static readonly DependencyProperty ElementsProperty = DependencyProperty.Register("Elements", typeof(List<FrameworkElement>), typeof(MyBehavior), new UIPropertyMetadata(new List<FrameworkElement>()));

public List<FrameworkElement> Elements
{
    get { return (List<FrameworkElement>) GetValue(ElementsProperty); }
    set { SetValue(ElementsProperty, value); }
}

(And I've followed the advice here to initialize the list in the behavior's constructor.) But I can't figure out how to bind the list of elements to this property from the view's XAML. (并且我遵循了这里的建议行为的构造函数中初始化列表。)但是我无法弄清楚如何从视图的XAML将元素列表绑定到此属性。 Basically, I want to do something along these lines: 基本上,我想按照以下方式做一些事情:

<Grid x:Name="Container">
    <i:Interaction:Behaviors>
        <local:MyBehavior>
            <local:MyBehavior.Elements>
                <Binding ElementName="FirstElement" />
                <Binding ElementName="SecondElement" />
                <Binding ElementName="ThirdElement" />
            </local:MyBehavior.Elements>
        </local:MyBehavior>
    </i:Interaction:Behaviors>
</Grid>

But of course this doesn't actually work. 但是当然这实际上不起作用。 I've tried MultiBinding here, but that doesn't work either. 我在这里尝试了MultiBinding,但这也不起作用。 Any idea what the XAML syntax would be for doing this, or is it even possible? 知道这样做的XAML语法是什么,或者甚至可能吗? If it's not possible, any ideas for other approaches to achieve this effect? 如果不可能的话,对实现此效果的其他方法有什么想法? Thanks! 谢谢!

I ended up solving this myself. 我最终自己解决了这个问题。 It turns out, I could use a MultiBinding for this. 事实证明,我可以为此使用MultiBinding。 The converter looks like this: 转换器看起来像这样:

public class MultiFrameworkElementConverter : IMultiValueConverter
{
    public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
    {
        return values != null ?
            values.Cast<FrameworkElement>().ToList() :
            new List<FrameworkElement>();
    }

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

I should be a little more thorough in that converter and ensure that all of the objects in the values[] array are of type FrameworkElement, but this gets the idea across. 我应该对该转换器进行更全面的检查,并确保values []数组中的所有对象的类型均为FrameworkElement,但这可以使您理解。 Then in the XAML I can bind to the property on my behavior like this: 然后在XAML中,我可以将行为绑定到属性,如下所示:

<local:MyBehavior.Elements>
    <MultiBinding Converter="{StaticResource MultiFrameworkElementConverter}" Mode="OneTime">
        <Binding ElementName="FirstElement" />
        <Binding ElementName="SecondElement" />
        <Binding ElementName="ThirdElement" />
    </MultiBinding>
</local:MyBehavior.Elements>

I'm using the "OneTime" mode on the binding simply because these are UI elements in the view that I'm binding to the behavior. 我在绑定上使用“ OneTime”模式仅仅是因为这些是我绑定到行为的视图中的UI元素。 They will never change during the lifetime of the view and behavior. 在视图和行为的生命周期中,它们永远不会改变。 So no need to ever update the binding. 因此,无需更新绑定。

Overall, I'm satisfied with this. 总的来说,我对此感到满意。 I can now allow the behavior to affect an arbitrary list of UI elements regardless of which view I use it on. 现在,无论我在哪个视图上使用它,我都可以允许该行为影响UI元素的任意列表。 I hope this description is able to help someone else trying to do something similar. 我希望这个描述能够帮助其他尝试做类似事情的人。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM