4

I have a listbox with a bit of templating. Groups are represented by expanders. The listbox is linked to the filesystem and each folder gets its own expander. Any time a file is renamed, deleted, etc, the listbox's view is refreshed. This works great but once the refresh is called, each of the expanders collapses. I can't seem to find a good way to keep them open. I saw another question that used binding to solve this for a single expander. The issue with a data binding on the "IsExpanded" is that there are an unknown number of expanders and I have no way of knowing how many there will be, what they will be called, etc at design time. Any ideas?

<ListBox.GroupStyle>
        <GroupStyle>
           <GroupStyle.ContainerStyle>
              <Style TargetType="{x:Type GroupItem}">
                 <Setter Property="Template">
                    <Setter.Value>
                       <ControlTemplate TargetType="{x:Type GroupItem}">
                          <Expander VerticalAlignment="Top"
                              OverridesDefaultStyle="True"
                              Template="{StaticResource SimpleExpanderTemp}">
                             <Expander.Header>
                                <TextBlock VerticalAlignment="Center"
                                     Background="Transparent"
                                     Text="{Binding Path=Name}"
                                           FontFamily="SegoeUI"
                                     FontSize="16"
                                     Foreground="Black"/>
                             </Expander.Header>
                             <Expander.Tag>
                                <LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
                                   <GradientStop Offset="0.0" Color="#696969" />
                                   <GradientStop Offset="1.0" Color="#474747" />
                                </LinearGradientBrush>
                             </Expander.Tag>
                             <ItemsPresenter/>
                          </Expander>
                       </ControlTemplate>
                    </Setter.Value>
                 </Setter>
              </Style>
           </GroupStyle.ContainerStyle>
        </GroupStyle>
     </ListBox.GroupStyle>
steveg89
  • 1,807
  • 2
  • 15
  • 29
  • 4
    Related question http://stackoverflow.com/q/2808777/620360. – LPL Jul 24 '12 at 19:45
  • @LPL If you could make that an answer, I'll award you. That link solved my issue completely. I can't believe I couldn't find that solution! thanks – steveg89 Jul 24 '12 at 20:17
  • 1
    This is not my award. Give that answer an upvote when you've earned the privilege. – LPL Jul 24 '12 at 20:30

1 Answers1

3

One possible solution is to still use data binding on the IsExpanded property.

Instead of binding to a boolean, bind to a list of booleans and use a ValueConverter to retrieve the appropriate item from the list.

When creating all your expanders, give each one an index number, if you're not already. Then when you bind the IsExpanded property, set the Converter, and set the converter parameter to the index number of the expander. Then your converter will receive the list of boolean values as the 'value' argument and the index number as the 'parameter' argument and your converter can then return a boolean value.

Your converter might look like this:

public class ListToBooleanConverter : IValueConverter
{

  public object Convert(object value, System.Type targetType, object parameter, System.Globalization.CultureInfo culture)
  {
    if ((value != null) & (parameter != null)) {
      try {
        Int16 itmNum = Convert.ToInt32(parameter);
        List<bool> lst = value;
        return lst[itmNum];
      } catch (Exception ex) {
        return null;
      }
    }
      return null;
  }

  public object ConvertBack(object value, System.Type targetType, object parameter, System.Globalization.CultureInfo culture)
  {
    throw new NotImplementedException("This method or operation is not implemented.");
  }
}

In XAML, the implementation of this data binding and converter would look like this (for the expander with an index number of 5):

IsExpanded="{Binding Path=ListIsExpanded, Converter={StaticResource ListToBooleanConverter}, ConverterParameter=5}">

Obviously, in code, this implementation will look a little different.

Stewbob
  • 16,759
  • 9
  • 63
  • 107
  • I don't explicitly create my expanders, I simply set the containerstyle. I'll give an example of what i do in the OP. – steveg89 Jul 24 '12 at 18:42
  • With that being the case, I don't see an obvious easy way to do it, short of iterating through the expanders just before the refresh and recording their state, then resetting them after the refresh. In your 'SimpleExpanderTemp' template, make sure that you don't set the IsExpanded property to False by default. Hopefully, someone else will have some better input. – Stewbob Jul 24 '12 at 19:12
  • 1
    Since this is the only other acceptable answer I got, I'll accept it. it doesn't solve my issue, but may solve someone else's – steveg89 Jul 24 '12 at 21:21