代码之家  ›  专栏  ›  技术社区  ›  Holger Adam

如何在listview的组头中保存IsExpanded状态

  •  16
  • Holger Adam  · 技术社区  · 16 年前

    我有个棘手的问题:

    <CollectionViewSource x:Key="ListViewObjects">
       <CollectionViewSource.Source>
          <Binding Path="CurrentListViewData"/>
       </CollectionViewSource.Source>
       <CollectionViewSource.GroupDescriptions>
          <PropertyGroupDescription PropertyName="ObjectType" />
       </CollectionViewSource.GroupDescriptions>
    </CollectionViewSource>
    

    在ListView中,我使用如下自定义组标题:

    <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>
                                  <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>
    

    如您所见,扩展器的IsExpanded属性设置为true。这意味着每当刷新ListView时,所有扩展控件都会展开。

    有人能给我一个提示或一个解决方案的想法吗

    3 回复  |  直到 16 年前
        1
  •  9
  •   Kieren Johnstone    16 年前

        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;
            }
        }
    

    然后,在某个ResourceDictionary中实例化它,并将IsExpanded绑定到它,如下所示:

    <Expander IsExpanded="{Binding Source={StaticResource myExpMgr}, Path=[Items[0].ObjectType]}">
    

    这很可能做到:一种让WPF在需要时调用代码并传递参数的好方法(WPF允许您将子表达式放在绑定路径的索引器中,这对我来说是个新闻—虽然很好,但不是吗!)

        2
  •  19
  •   aKzenT    13 年前

    如评论中所解释的,公认的答案是错误的。我编写了以下实现所需功能的行为:

    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
    }
    

    ItemsControl 它保存每个组项的展开状态。即使控件中的项发生了变化,这也将是一个内固定过程。

    <Expander>
        <i:Interaction.Behaviors>
            <behaviors:PersistGroupExpandedStateBehavior GroupName="{Binding Name}" />
        </i:Interaction.Behaviors>
        ...
    </Expander>
    
        3
  •  1
  •   JKennedy Ziyad Godil    12 年前

    带标记的答案在.NET4.5中不起作用。

    一个简单的解决方法是添加

        private bool _isExpanded = true;
        public bool IsExpanded
        {
            get { return _isExpanded; }
            set { _isExpanded = value; }
        }
    

    属性设置为ViewModel(在本例中,不管对象是什么 CurrentListViewData 持有)

    然后做:

    <Expander IsExpanded="{Binding Items[0].IsExpanded}">
    

    简单而有效,就像WPF应该的那样