开发者

XAML trigger setter and property of UIElementCollection type

开发者 https://www.devze.com 2023-02-07 18:26 出处:网络
My control has property Buttons of type UIElementCollection. Is it possible to modify such property via triggers (specifically DataTrigger)?

My control has property Buttons of type UIElementCollection. Is it possible to modify such property via triggers (specifically DataTrigger)?

I have following code:

<Setter Property="Buttons">
    <Setter.Value>
        <Button>A</Button>
        <Button>B</Button>
    </Setter.Value>
</Setter>

And I get error "The property value is set more than once". Wrapping the buttons in UIElementCollection tag doesn't work (UIElementCollection has no default contructor). If I remove the second button, I g开发者_StackOverflow中文版et exception that the Buttons property is not compatible with type Button.

Thanks for any help


You can use an attached behavior to modify a collection with a setter. Here is a working example based on the Panel.Children property which is also a UIElementCollection:

<Grid>
    <Grid.Resources>
        <Style x:Key="twoButtons" TargetType="Panel">
            <Setter Property="local:SetCollection.Children">
                <Setter.Value>
                    <x:Array Type="UIElement">
                        <Button Content="Button1"/>
                        <Button Content="Button2"/>
                    </x:Array>
                </Setter.Value>
            </Setter>
        </Style>
    </Grid.Resources>
    <StackPanel Style="{StaticResource twoButtons}"/>
</Grid>

And here is the attached property SetCollection.Children:

public static class SetCollection
{
    public static ICollection<UIElement> GetChildren(DependencyObject obj)
    {
        return (ICollection<UIElement>)obj.GetValue(ChildrenProperty);
    }

    public static void SetChildren(DependencyObject obj, ICollection<UIElement> value)
    {
        obj.SetValue(ChildrenProperty, value);
    }

    public static readonly DependencyProperty ChildrenProperty =
        DependencyProperty.RegisterAttached("Children", typeof(ICollection<UIElement>), typeof(SetCollection), new UIPropertyMetadata(OnChildrenPropertyChanged));

    static void OnChildrenPropertyChanged(object sender, DependencyPropertyChangedEventArgs e)
    {
        var panel = sender as Panel;
        var children = e.NewValue as ICollection<UIElement>;
        panel.Children.Clear();
        foreach (var child in children) panel.Children.Add(child);
    }
}


Edit: A workaround would be using a converter, define your Buttons in a list in some resources:

    <col:ArrayList x:Key="Buttons">
        <Button>A</Button>
        <Button>B</Button>
    </col:ArrayList>

Namespace: xmlns:col="clr-namespace:System.Collections;assembly=mscorlib"

And use a custom converter in the setter to turn it into a collection:

<Setter Property="Buttons" Value="{Binding Source={StaticResource Buttons}, Converter={StaticResource ListToUIElementCollectionConverter}}"/>

Edit: Getting this to work properly is not a trivial task since the converter needs to know the parent object for the UIElementCollection-constructor.


In the end, I decided to circumvent the issue by modifying (with triggers) individual items of the collection (individual buttons) instead of changing whole collection.

I just hide and show the buttons depending on some conditions.

0

精彩评论

暂无评论...
验证码 换一张
取 消