user381624
user381624

Reputation: 676

How do I trigger a WPF expander IsExpanded property from another expander's IsExpanded property

I have two expanders, side by side. I want only one to be expanded at a time. So if one is expanded, and the user expands the other, I want the first one to collapse. The user can have both collapsed, and both collapsed is the starting state.

As can be seen in the code, I have included the "Header" property as a test, and it works as expected, but the IsExpanded property is not working.

<Expander x:Name="emailExpander">
  <Expander.Style>
    <Style TargetType="Expander">
      <Setter Property="IsExpanded" Value="False"/>
      <Setter Property="Header" Value="Email"/>
      <Style.Triggers>
        <DataTrigger Binding="{Binding IsExpanded,ElementName=customerExpander}" Value="True">
          <Setter Property="IsExpanded" Value="False"/>
          <Setter Property="Header" Value="other expanded"/>
        </DataTrigger>
      </Style.Triggers>
    </Style>
  </Expander.Style>      
</Expander>

Upvotes: 2

Views: 12331

Answers (3)

Doctus Scholaris
Doctus Scholaris

Reputation: 77

This can be handled by binding to a view object with a little logic added.

In your WPF bind the IsExpanded property to the EmailExpanded and CustomerExpanded properties of the view.

<Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="1*"/>
        <ColumnDefinition Width="1*"/>
    </Grid.ColumnDefinitions>
    <Expander Grid.Column="0" Header="Email" IsExpanded="{Binding EmailExpanded}">
        <TextBlock Text="Email Data"/>
    </Expander>
    <Expander Grid.Column="1" Header="Customer" IsExpanded="{Binding CustomerExpanded}">
        <TextBlock Text="Customer Data"/>
    </Expander>
</Grid>

Assign the view in your main Window.

public MainWindow()
{
    InitializeComponent();

    DataContext = new View();
}

Then make your view class something like the following.

class View : INotifyPropertyChanged
{
    private bool _CustomerExpanded;
    public bool CustomerExpanded
    {
        get
        {
            return _CustomerExpanded;
        }
        set
        {
            if (_CustomerExpanded != value)
            {
                // Add logic to close Email Expander
                if (value)
                {
                    EmailExpanded = false;
                }

                _CustomerExpanded = value;
                OnPropertyChanged("CustomerExpanded");
            }
        }
    }

    private bool _EmailExpanded;
    public bool EmailExpanded
    {
        get
        {
            return _EmailExpanded;
        }
        set
        {
            if (_EmailExpanded != value)
            {
                // Add logic to close Customer Expander
                if (value)
                {
                    CustomerExpanded = false;
                }

                _EmailExpanded = value;
                OnPropertyChanged("EmailExpanded");
            }
        }
    }

    protected void OnPropertyChanged(string propertyName)
    {
        PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }

    public event PropertyChangedEventHandler PropertyChanged = delegate { };
}

Notice the addition to the setters. Collapsing an expander will have no effect on the other expander, but expanding one will cause the other to collapse. No stack overflow :)

Upvotes: 1

Tri Q Tran
Tri Q Tran

Reputation: 5690

What you're better off doing is use an accordion control released in the WPF Toolkit V2. Very handy and no "Stack Overflow" exceptions. =)

Upvotes: 0

arinto
arinto

Reputation: 143

I found the answer in this post: WPF Expanders Triggers

Use BoolInverterConverter in the answer above and here is the code snippets for your case

<Window x:Class="WpfApplication1.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:WpfApplication1"
    Title="MainWindow" Height="350" Width="525">
<Window.Resources>
    <local:BoolInverterConverter x:Key="bic"/>
</Window.Resources>
<Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition />
        <ColumnDefinition />
    </Grid.ColumnDefinitions>
    <Expander x:Name="emailExpander" IsExpanded="{Binding ElementName=customerExpander, Converter={StaticResource bic}, Path=IsExpanded}">
        <Expander.Style>
            <Style TargetType="Expander">
                <Setter Property="Header" Value="Email"/>
            </Style>
        </Expander.Style>
        <StackPanel Margin="10,4,0,0">
            <CheckBox Margin="4" Content="Email 1" />
            <CheckBox Margin="4" Content="Email 2" />
            <CheckBox Margin="4" Content="Email 3" />
        </StackPanel>
    </Expander>
    <Expander x:Name="customerExpander" Grid.Column="1"> 
        <Expander.Style>
            <Style TargetType="Expander">
                <Setter Property="Header" Value="Customer"/>
            </Style>
        </Expander.Style>
        <StackPanel Margin="10,4,0,0">
            <CheckBox Margin="4" Content="Customer 1" />
            <CheckBox Margin="4" Content="Customer 2" />
            <CheckBox Margin="4" Content="Customer 3" />
        </StackPanel>
    </Expander>
</Grid>

Upvotes: 0

Related Questions