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

C# 将元素列表绑定到WPF中基于集合的依赖项属性,c#,wpf,xaml,C#,Wpf,Xaml,我正在WPF应用程序(.Net 4.5)中实现自定义混合行为。我向行为类添加了两个FrameworkElement类型的依赖属性,以允许行为用户绑定他们想要控制的视图元素。(这种行为会在多个元素上调用一些动画,所以我不能只使用AssociatedObject)。这很好,基本上如下所示: public class MyBehavior : Behavior<FrameworkElement> { public static readonly DependencyProperty

我正在WPF应用程序(.Net 4.5)中实现自定义混合行为。我向行为类添加了两个FrameworkElement类型的依赖属性,以允许行为用户绑定他们想要控制的视图元素。(这种行为会在多个元素上调用一些动画,所以我不能只使用AssociatedObject)。这很好,基本上如下所示:

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); }
    }
}
<Grid x:Name="Container">
    <i:Interaction:Behaviors>
        <local:MyBehavior
            Element1="{Binding ElementName=FirstElement}"
            Element2="{Binding ElementName=SecondElement}"
        />
    </i:Interaction:Behaviors>
</Grid>
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); }
}
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();
    }
}
<local:MyBehavior.Elements>
    <MultiBinding Converter="{StaticResource MultiFrameworkElementConverter}" Mode="OneTime">
        <Binding ElementName="FirstElement" />
        <Binding ElementName="SecondElement" />
        <Binding ElementName="ThirdElement" />
    </MultiBinding>
</local:MyBehavior.Elements>
公共类MyBehavior:Behavior
{
public static readonly dependencProperty Element1Property=dependencProperty.Register(“Element1”、typeof(FrameworkElement)、typeof(MyBehavior)、new UIPropertyMetadata());
公共框架元素元素1
{
获取{return(FrameworkElement)GetValue(Element1Property);}
set{SetValue(Element1Property,value);}
}
public static readonly dependencProperty Element2Property=dependencProperty.Register(“Element2”、typeof(FrameworkElement)、typeof(MyBehavior)、new UIPropertyMetadata());
公共框架元素元素2
{
获取{return(FrameworkElement)GetValue(Element2Property);}
set{SetValue(Element2Property,value);}
}
}
标准的依赖属性。在我看来,我可以这样使用:

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); }
    }
}
<Grid x:Name="Container">
    <i:Interaction:Behaviors>
        <local:MyBehavior
            Element1="{Binding ElementName=FirstElement}"
            Element2="{Binding ElementName=SecondElement}"
        />
    </i:Interaction:Behaviors>
</Grid>
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); }
}
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();
    }
}
<local:MyBehavior.Elements>
    <MultiBinding Converter="{StaticResource MultiFrameworkElementConverter}" Mode="OneTime">
        <Binding ElementName="FirstElement" />
        <Binding ElementName="SecondElement" />
        <Binding ElementName="ThirdElement" />
    </MultiBinding>
</local:MyBehavior.Elements>

这非常有效,我可以处理行为中的元素。但是现在我需要绑定一个这样的元素列表。所以我不能提前知道有2个元素,可能有N个元素需要处理。因此,我向MyBehavior类添加了另一个属性,如下所示:

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); }
    }
}
<Grid x:Name="Container">
    <i:Interaction:Behaviors>
        <local:MyBehavior
            Element1="{Binding ElementName=FirstElement}"
            Element2="{Binding ElementName=SecondElement}"
        />
    </i:Interaction:Behaviors>
</Grid>
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); }
}
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();
    }
}
<local:MyBehavior.Elements>
    <MultiBinding Converter="{StaticResource MultiFrameworkElementConverter}" Mode="OneTime">
        <Binding ElementName="FirstElement" />
        <Binding ElementName="SecondElement" />
        <Binding ElementName="ThirdElement" />
    </MultiBinding>
</local:MyBehavior.Elements>
public static readonly dependencProperty ElementsProperty=dependencProperty.Register(“元素”、typeof(列表)、typeof(MyBehavior)、newUIPropertyMetadata(new List());
公共列表元素
{
get{return(List)GetValue(ElementsProperty);}
set{SetValue(elementsprroperty,value);}
}
(我已经按照建议在行为的构造函数中初始化了列表。)但是我不知道如何从视图的XAML中将元素列表绑定到这个属性。基本上,我想做以下几点:

<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>


但这当然不起作用。我在这里尝试了多重绑定,但也不起作用。你知道XAML的语法是什么吗,或者说它是可能的吗?如果不可能的话,有没有其他方法可以达到这个效果?谢谢

最后我自己解决了这个问题。事实证明,我可以使用多重绑定。转换器如下所示:

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); }
    }
}
<Grid x:Name="Container">
    <i:Interaction:Behaviors>
        <local:MyBehavior
            Element1="{Binding ElementName=FirstElement}"
            Element2="{Binding ElementName=SecondElement}"
        />
    </i:Interaction:Behaviors>
</Grid>
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); }
}
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();
    }
}
<local:MyBehavior.Elements>
    <MultiBinding Converter="{StaticResource MultiFrameworkElementConverter}" Mode="OneTime">
        <Binding ElementName="FirstElement" />
        <Binding ElementName="SecondElement" />
        <Binding ElementName="ThirdElement" />
    </MultiBinding>
</local:MyBehavior.Elements>
公共类多框架元素转换器:IMultiValueConverter
{
公共对象转换(对象[]值,类型targetType,对象参数,CultureInfo区域性)
{
返回值!=null?
values.Cast().ToList():
新列表();
}
公共对象[]转换回(对象值,类型[]目标类型,对象参数,CultureInfo区域性)
{
抛出新的NotImplementedException();
}
}
我应该更深入地了解这个转换器,并确保values[]数组中的所有对象都是FrameworkElement类型的,但这让我明白了这一点。然后在XAML中,我可以绑定到我行为的属性,如下所示:

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); }
    }
}
<Grid x:Name="Container">
    <i:Interaction:Behaviors>
        <local:MyBehavior
            Element1="{Binding ElementName=FirstElement}"
            Element2="{Binding ElementName=SecondElement}"
        />
    </i:Interaction:Behaviors>
</Grid>
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); }
}
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();
    }
}
<local:MyBehavior.Elements>
    <MultiBinding Converter="{StaticResource MultiFrameworkElementConverter}" Mode="OneTime">
        <Binding ElementName="FirstElement" />
        <Binding ElementName="SecondElement" />
        <Binding ElementName="ThirdElement" />
    </MultiBinding>
</local:MyBehavior.Elements>

我在绑定上使用“OneTime”模式只是因为这些是视图中的UI元素,我正在绑定到行为。在视图和行为的生命周期中,它们永远不会改变。因此,无需更新绑定


总的来说,我对此感到满意。我现在可以允许该行为影响任意的UI元素列表,而不管我在哪个视图上使用它。我希望此描述能够帮助其他试图做类似事情的人。

第一个元素,
第二个元素
,。。。定义您可以做的一件事是在模型和UI之间放置一个
ValueConverter
。然后在转换器内部,查询元素并返回一个
列表
对象。这些只是在同一视图中定义的其他UI元素。请注意,这是尝试将W视图中的元素绑定到行为对象而不是视图模型的情况。我可以轻松地绑定单个元素,但还没有弄清楚如何绑定它们的列表。我认为ValueConverter对此没有帮助。我不想改变他们。我只想指定一些行为可以使用的元素。