我有一个非常棘手的问题:
我正在使用ListView控件,其ItemsSource设置为CollectionViewSource,包括PropertyGroupDescription以对ListView元素进行分组。 CollectionViewSource如下所示:
<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>
正如您所看到的,Expander的IsExpanded属性设置为true。这意味着无论何时刷新ListView,都会扩展所有Expander控件。
但我想保存每个Expander的最后状态。我无法找到一种方法来保存每个ObjectType的Expander状态列表。我正在尝试使用绑定的HashTable和Converter,但是我没有将ObjectType作为ConverterParameter提供,因为它总是作为字符串传递。但无论如何,这可能不是解决方案。
有人可以给我一个解决方案的暗示或想法吗? :)
答案 0 :(得分:15)
如评论中所述,接受的答案是错误的。我写了以下行为,实现了所需的功能:
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>
答案 1 :(得分:9)
你可以创建一个带有Dictionary的新类(比如,ObjectType作为bool值的关键字),并给它一个索引器:
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 :(得分:2)
标记的答案在.Net 4.5中不起作用。
一个简单的解决方案是添加
private bool _isExpanded = true;
public bool IsExpanded
{
get { return _isExpanded; }
set { _isExpanded = value; }
}
属性到您的ViewModel(在这种情况下,无论对象CurrentListViewData
持有)
然后执行:
<Expander IsExpanded="{Binding Items[0].IsExpanded}">
在你的模板上。
就像WPF一样简单有效