I have quite a tricky problem:
I am using a ListView control with the ItemsSource set to a CollectionViewSource including a PropertyGroupDescription to group the ListView elements. The CollectionViewSource looks like this:
<CollectionViewSource x:Key="ListViewObjects">
   <CollectionViewSource.Source>
      <Binding Path="CurrentListViewData"/>
   </CollectionViewSource.Source>
   <CollectionViewSource.GroupDescriptions>
      <PropertyGroupDescription PropertyName="ObjectType" />
   </CollectionViewSource.GroupDescriptions>
</CollectionViewSource>
In the ListView I use customize the group headers like this:
<ListView.GroupStyle>
   <GroupStyle>
      <GroupStyle.ContainerStyle>
         <Style TargetType="{x:Type GroupItem}">
            <Setter Property="Margin" Value="5"/>
            <Setter Property="Template">
               <Setter.Value>
                  <ControlTemplate TargetType="{x:Type GroupItem}">
                     <Expander IsExpanded="True">
                        <Expander.Header>
                           <DockPanel>
                             开发者_JS百科 <TextBlock Text="{Binding Path=Items[0].ObjectType />
                           </DockPanel>
                        </Expander.Header>
                        <Expander.Content>
                           <ItemsPresenter />
                        </Expander.Content>
                     </Expander>
                  </ControlTemplate>
               </Setter.Value>
            </Setter>
         </Style>
      </GroupStyle.ContainerStyle>
   </GroupStyle>
</ListView.GroupStyle>
As you can see the IsExpanded property of the Expander is set to true. This means that whenever the ListView is refreshed, all Expander controls are expanded.
I do however want to save the last state of every Expander. I haven't been able to figure out a way to save a list of Expander states per ObjectType. I was experimenting with a bound HashTable and a Converter, but I failed at providing the ObjectType as a ConverterParameter, because it was always passed as a string. But that may not be the solution anyways.
Can somebody give me a hint or an idea for a solution, please? :)
The accepted answer is wrong as explained in the comments. I wrote the following behavior which achieves the desired functionality:
public class PersistGroupExpandedStateBehavior : Behavior<Expander>
{
    #region Static Fields
    public static readonly DependencyProperty GroupNameProperty = DependencyProperty.Register(
        "GroupName", 
        typeof(object), 
        typeof(PersistGroupExpandedStateBehavior), 
        new PropertyMetadata(default(object)));
    private static readonly DependencyProperty ExpandedStateStoreProperty =
        DependencyProperty.RegisterAttached(
            "ExpandedStateStore", 
            typeof(IDictionary<object, bool>), 
            typeof(PersistGroupExpandedStateBehavior), 
            new PropertyMetadata(default(IDictionary<object, bool>)));
    #endregion
    #region Public Properties
    public object GroupName
    {
        get
        {
            return (object)this.GetValue(GroupNameProperty);
        }
        set
        {
            this.SetValue(GroupNameProperty, value);
        }
    }
    #endregion
    #region Methods
    protected override void OnAttached()
    {
        base.OnAttached();
        bool? expanded = this.GetExpandedState();
        if (expanded != null)
        {
            this.AssociatedObject.IsExpanded = expanded.Value;
        }
        this.AssociatedObject.Expanded += this.OnExpanded;
        this.AssociatedObject.Collapsed += this.OnCollapsed;
    }
    protected override void OnDetaching()
    {
        this.AssociatedObject.Expanded -= this.OnExpanded;
        this.AssociatedObject.Collapsed -= this.OnCollapsed;
        base.OnDetaching();
    }
    private ItemsControl FindItemsControl()
    {
        DependencyObject current = this.AssociatedObject;
        while (current != null && !(current is ItemsControl))
        {
            current = VisualTreeHelper.GetParent(current);
        }
        if (current == null)
        {
            return null;
        }
        return current as ItemsControl;
    }
    private bool? GetExpandedState()
    {
        var dict = this.GetExpandedStateStore();
        if (!dict.ContainsKey(this.GroupName))
        {
            return null;
        }
        return dict[this.GroupName];
    }
    private IDictionary<object, bool> GetExpandedStateStore()
    {
        ItemsControl itemsControl = this.FindItemsControl();
        if (itemsControl == null)
        {
            throw new Exception(
                "Behavior needs to be attached to an Expander that is contained inside an ItemsControl");
        }
        var dict = (IDictionary<object, bool>)itemsControl.GetValue(ExpandedStateStoreProperty);
        if (dict == null)
        {
            dict = new Dictionary<object, bool>();
            itemsControl.SetValue(ExpandedStateStoreProperty, dict);
        }
        return dict;
    }
    private void OnCollapsed(object sender, RoutedEventArgs e)
    {
        this.SetExpanded(false);
    }
    private void OnExpanded(object sender, RoutedEventArgs e)
    {
        this.SetExpanded(true);
    }
    private void SetExpanded(bool expanded)
    {
        var dict = this.GetExpandedStateStore();
        dict[this.GroupName] = expanded;
    }
    #endregion
}
It attaches a dictionary to the containing ItemsControl which saves the expanded state for every group item. This will be peristent, even if the items in the control changes.
Usage:
<Expander>
    <i:Interaction.Behaviors>
        <behaviors:PersistGroupExpandedStateBehavior GroupName="{Binding Name}" />
    </i:Interaction.Behaviors>
    ...
</Expander>
You could create a new class with a Dictionary (say, ObjectType as a key to bool values), and give it an indexer:
    Dictionary<ObjectType, bool> expandStates = new Dictionary<ObjectType, bool>();
    public bool this[ObjectType key]
    {
        get
        {
            if (!expandStates.ContainsKey(key)) return false;
            return expandStates[key];
        }
        set
        {
            expandStates[key] = value;
        }
    }
Then, instantiate it in a ResourceDictionary somewhere and bind the IsExpanded to it like this:
<Expander IsExpanded="{Binding Source={StaticResource myExpMgr}, Path=[Items[0].ObjectType]}">
That might well do it: a nice way of getting WPF to call your code and pass a parameter just when you need it. (That WPF lets you put subexpressions in indexers in a binding path was news to me - good though isn't it!)
The marked Answer Doesn't work in .Net 4.5.
A simple solution for this is to add a
    private bool _isExpanded = true;
    public bool IsExpanded
    {
        get { return _isExpanded; }
        set { _isExpanded = value; }
    }
property to your ViewModel (In this case Whatever objects  CurrentListViewData holds)
and then do:
<Expander IsExpanded="{Binding Items[0].IsExpanded}">
on your template.
Simple and effective just like WPF should be
 
         
                                         
                                         
                                         
                                        ![Interactive visualization of a graph in python [closed]](https://www.devze.com/res/2023/04-10/09/92d32fe8c0d22fb96bd6f6e8b7d1f457.gif) 
                                         
                                         
                                         
                                         加载中,请稍侯......
 加载中,请稍侯......
      
精彩评论