Llarian
Llarian

Reputation: 81

Obscure binding behaviour

I have a custom TabItem:

public class FooTabItem : TabItem
{
    public static readonly DependencyProperty ButtonsProperty =
        DependencyProperty.Register("Buttons", typeof(List<Button>), typeof(FooTabItem), new PropertyMetadata(new List<Button>()));


    public List<Button> Buttons
    {
        get => (List<Button>) GetValue(ButtonsProperty);
        set => SetValue(ButtonsProperty, value);
    }
}

and the following using in may view:

[...]
    <Grid Grid.Row="0">
[...]
        <Label Grid.Column="0" Content="{Binding ElementName=TabControl, Path=SelectedItem.Header}" />
        <ItemsControl Grid.Column="3" HorizontalAlignment="Right" ItemsSource="{Binding ElementName=TabControl, Path=SelectedItem.Buttons}">
            <ItemsControl.ItemsPanel>
                <ItemsPanelTemplate>
                    <WrapPanel Orientation="Horizontal" FlowDirection="RightToLeft" />
                </ItemsPanelTemplate>
            </ItemsControl.ItemsPanel>
        </ItemsControl>
    </Grid>
    <TabControl Grid.Row="1" x:Name="TabControl" TabStripPlacement="Left">
        <TabControl.Items>
            <local:FooTabItem x:Name="First" Header="abc">
                <local:FooTabItem.Buttons>
                    <Button Content="a23"/>
                    <Button Content="a56"/>
                    <Button Content="a89"/>
                </local:FooTabItem.Buttons>
            </local:FooTabItem>
            <local:FooTabItem x:Name="Second" Header="def">
                <local:FooTabItem.Buttons>
                    <Button Content="rfv"/>
                    <Button Content="tgb"/>
                </local:FooTabItem.Buttons>
            </local:FooTabItem>
        </TabControl.Items>
    </TabControl>
</Grid>

enter image description here

I'd expected three respectively two buttons depending on the selcted tab, but I get all five. Why and how to fix this?

Upvotes: 0

Views: 42

Answers (2)

mm8
mm8

Reputation: 169200

Initialize the dependency property in the constructor of the control:

public class FooTabItem : TabItem
{
    public FooTabItem()
    {
        Buttons = new List<Button>();
    }

    public static readonly DependencyProperty ButtonsProperty =
        DependencyProperty.Register("Buttons", typeof(List<Button>), typeof(FooTabItem));

    public List<Button> Buttons
    {
        get { return (List<Button>)GetValue(ButtonsProperty); }
        set { SetValue(ButtonsProperty, value); }
    }
}

Collection-Type Dependency Properties: https://learn.microsoft.com/en-us/dotnet/framework/wpf/advanced/collection-type-dependency-properties

[...]Therefore you must be careful to not use the singular static collection defined by the collection property metadata as the working default value for newly created instances of your type. Instead, you must make sure that you deliberately set the collection value to a unique (instance) collection as part of your class constructor logic.

Upvotes: 4

Titian Cernicova-Dragomir
Titian Cernicova-Dragomir

Reputation: 249536

The behavior is caused by the fact that you set the default value of the object to new List<Button>(). This means that unless explicitly set you will have the same instance of List<Button> for all objects in the Buttons property.

The syntax you use for the Buttons property, implies that you are adding to an existing list not creating a new list.

You could try creating a class :

class ListOfButtons : List<Button>
{
}

Not setting a default value for the property and in XAML create a fresh instance of the ListOfButtons:

 <local:FooTabItem.Buttons>
     <local:ListOfButtons>
         <Button x:Name="a23"/>
         <Button x:Name="a56"/>
         <Button x:Name="a89"/>
     </local:ListOfButtons>
 </local:FooTabItem.Buttons>

Upvotes: 4

Related Questions