Introduction

Many people have found the Accordian control not flexible enough or a little buggy, or they don't want to add the WPF Toolkit to their project. However the Accordian is essentially just a grouped bunch of Expanders with animated open and close. This is easy to recreate with a ValueConverter on IsExpanded. This gives developers much more flexability over layout and design.
 

Building the Sample

Just download, unblock, unzip, open and run!
 
Description
This project has three examples included. 
The first shows just the power of the Converter to group the Expanders.
The second shows one of many solutions for animating, borrowed from Matt Serbinski's blog
 
The third example shows how you can generate the expanders from a collection, in a ListBox, just like the Accordian.
 

Example 1 - ValueConverter

The trick is to set the IsExpanded property of each Expander control from a code-behind property.
  
C#
Edit|Remove
        string _CurrentExpanded; 
        public string CurrentExpanded 
        { 
            get 
            { 
                return _CurrentExpanded; 
            } 
            set 
            { 
                if (_CurrentExpanded != value) 
                { 
                    _CurrentExpanded = value; 
                    RaisePropertyChanged("CurrentExpanded"); 
                } 
            } 
        }
The property is just a string representing the NAME of the currently expanded control.
The IsExpanded binding used a ValueConverter, passing in the CurrentExpanded property and setting the ConverterParameter to that control's given name (in my example just a  number 1-3)
XAML
Edit|Remove
<StackPanel Margin="20"> 
    <Expander Header="Expander one" IsExpanded="{Binding CurrentExpanded, Converter={StaticResource ExpandedConverter}, ConverterParameter=1}"> 
        <TextBlock Text="ONE"/> 
    </Expander> 
    <Expander Header="Expander two" IsExpanded="{Binding CurrentExpanded, Converter={StaticResource ExpandedConverter}, ConverterParameter=2}"> 
        <TextBlock Text="TWO"/> 
    </Expander> 
    <Expander Header="Expander three" IsExpanded="{Binding CurrentExpanded, Converter={StaticResource ExpandedConverter}, ConverterParameter=3}"> 
        <TextBlock Text="THREE"/> 
    </Expander> 
</StackPanel>
 
And finally, here is the ValueConverter that decides whether to return IsExpanded true or false, depending whether the control name is the same as the bound value.
C#
Edit|Remove
public class ExpandedConverter : IValueConverter 
{ 
    public object Convert(object value, System.Type targetType, object parameter, System.Globalization.CultureInfo culture) 
    { 
        return ((string)value == (string)parameter); 
    } 
 
    public object ConvertBack(object value, System.Type targetType, object parameter, System.Globalization.CultureInfo culture) 
    { 
        return parameter; 
    } 
}
 
 
Notice the ConvertBack method is used in this example, as the binding is TwoWay. When an expander is manually expanded, the parameter (control name) is passed back to the code-behind property. Because I implement INotifyPropertyChanged, the PropertyChanged event causes all the other expanders to update their binding and close.
 

Example 2 - Animation


I've added the second example of animated Expanders just to pad out the project and give you something extra. This project is mainly to teach about Grouping Expanders with a Value Converter, but the next natural step is to want to animate the opeining and closing. So I grabbed one of the better examples for that from Matt Serbinski, thanks to him for that.
 

Example 3 - Programattically Generating Grouped Expanders

 
The final example is for those that want to generate a dynamic number of Expanders, based on a collection. This uses a Datatemplate to define the Expanders.
 
XAML
Edit|Remove
<DataTemplate x:Key="DataTemplate1"> 
    <Expander Header="{Binding Header}" Content="{Binding Content}"> 
        <Expander.Resources> 
            <local:ExpandedMultiConverter x:Key="ExpandedMultiConverter"/> 
        </Expander.Resources> 
        <Expander.IsExpanded> 
            <MultiBinding Converter="{StaticResource ExpandedMultiConverter}"> 
                <Binding Path="CurrentExpanded3" Mode="TwoWay" ElementName="Window"/> 
                <Binding Path="ItemId" Mode="OneWay" /> 
            </MultiBinding> 
        </Expander.IsExpanded> 
    </Expander> 
</DataTemplate>
 
It uses a MultiBinding because the ConverterParameter is not a DependancyProperty, so you can bind and pass in a dynamic name to each Expander for the conversion.
 
 
Notice the Expander Content is a property is also passed in. This is a property of the bound ExpanderItem class:
 
C#
Edit|Remove
    public class ExpanderItem 
    { 
        public string Header { get; set; } 
        public string ItemId { get; set; } 
        public FrameworkElement Content { get; set; } 
    }
A collection of FrameworkElements could therefore be passed in and converted to this class. Then the collection of ExpanderItem generates the grouped Expanders automatically from the ItemTemplate above.
 
 
 

Source Code Files