如何根据WPF中的组名折叠/展开多个扩展控件?
我想要实现的是:折叠或展开组样式中共享相同组名的所有扩展器 我们有一个列表框和嵌套在其中的另一个列表框来显示子项。子项ItemsSource绑定到附加了组描述的CollectionView 组项目模板非常简单:如何根据WPF中的组名折叠/展开多个扩展控件?,wpf,expander,collectionviewsource,groupstyle,Wpf,Expander,Collectionviewsource,Groupstyle,我想要实现的是:折叠或展开组样式中共享相同组名的所有扩展器 我们有一个列表框和嵌套在其中的另一个列表框来显示子项。子项ItemsSource绑定到附加了组描述的CollectionView 组项目模板非常简单: <Expander IsExpanded="{Binding Path=WHAT_TO_DO, Mode=TwoWay}"> <Expander.Header> <TextBlock T
<Expander IsExpanded="{Binding Path=WHAT_TO_DO, Mode=TwoWay}">
<Expander.Header>
<TextBlock Text="{Binding Name}" />
</Expander.Header>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" SharedSizeGroup="{Binding Name, Converter={StaticResource GroupNameToUniqueNameConverter}}" />
</Grid.RowDefinitions>
<ItemsPresenter/>
</Grid>
</Expander>
我认为这不容易做到。这里可能有两种选择 1) 手动-绑定您需要的每个扩展器,例如组中的第一项或任何其他适当的内容
2) 更自动的方法可能需要编写一个类,该类有一个字典,其中保存每个组的状态。这里的问题是,控制器需要知道expander的哪个实例正在进行绑定,或者它在哪个组中。我在这里看到的一个解决方案是编写一个自定义转换器,它有一个带有dictionary的类的静态实例,并使用converter参数传递组/引用(您可以在这里使用绑定,因此在xaml中这是纯Ctrl+C,Ctrl+V操作)您可以在代码隐藏中迭代所有列表框项。对于每个listbox项,您应该查看它是否包含扩展器。如果是这样的话,你就把它展开或折叠。有关如何迭代项并查找特定控件的信息,请参见此链接
创建自己的控件-GroupExpander-从Expander中将其子类化 使用以下帮助器方法查找视觉层次结构中的任何父对象:
public static IEnumerable<T> RecurseParents<T>(this DependencyObject child)
{
if (child is T)
{
yield return Get<T>(child);
}
if (child != null)
{
foreach (var parent in RecurseParents<T>(child.GetParentObject()))
{
yield return parent;
}
}
}
public static DependencyObject GetParentObject(this DependencyObject child)
{
if (child == null) return null;
// handle content elements separately
var contentElement = child as ContentElement;
if (contentElement != null)
{
var parent = ContentOperations.GetParent(contentElement);
if (parent != null) return parent;
var fce = contentElement as FrameworkContentElement;
return fce != null ? fce.Parent : null;
}
// also try searching for parent in framework elements (such as DockPanel, etc)
var frameworkElement = child as FrameworkElement;
if (frameworkElement != null)
{
var parent = frameworkElement.Parent;
if (parent != null) return parent;
}
// if it's not a ContentElement/FrameworkElement, rely on VisualTreeHelper
return VisualTreeHelper.GetParent(child);
}
公共静态IEnumerable RecurseParents(此DependencyObject子对象)
{
如果(孩子是T)
{
收益-收益-获得(子项);
}
if(child!=null)
{
foreach(RecurseParents(child.GetParentObject())中的var parent)
{
收益母公司;
}
}
}
公共静态DependencyObject GetParentObject(此DependencyObject子对象)
{
if(child==null)返回null;
//分别处理内容元素
var contentElement=作为contentElement的子级;
if(contentElement!=null)
{
var parent=ContentOperations.GetParent(contentElement);
如果(parent!=null)返回parent;
var fce=contentElement作为FrameworkContentElement;
返回fce!=null?fce.父项:null;
}
//还可以尝试在框架元素(如DockPanel等)中搜索父元素
var frameworkElement=作为frameworkElement的子级;
if(frameworkElement!=null)
{
var parent=frameworkElement.parent;
如果(parent!=null)返回parent;
}
//如果不是ContentElement/FrameworkElement,请依赖VisualTreeHelper
返回VisualTreeHelper.GetParent(子级);
}
现在,通过查找父扩展器并计算这是哪个扩展器来编写查找GroupExpander级别的逻辑
您可以从以下代码中获得想法:
public class DataGridGroupExpander : GroupExpander
{
#region Class level variables
private bool mSettingIsExpanded = false;
#endregion
#region Constructors
public DataGridGroupExpander()
{
SetBinding(HeaderProperty, new Binding("Name"));
Loaded += DataGridGroupExpander_Loaded;
}
#endregion
#region Properties
#region Owner
private DataGrid mOwner = null;
public DataGrid Owner
{
get { return mOwner; }
private set
{
if (mOwner != value)
{
if (mOwner != null)
{
DetachOwner();
}
mOwner = value;
if (mOwner != null)
{
AttachOwner();
}
}
}
}
private void AttachOwner()
{
SetFieldName();
}
private void DetachOwner()
{
}
#endregion
#region ParentExpander
private DataGridGroupExpander mParentExpander = null;
public DataGridGroupExpander ParentExpander
{
get { return mParentExpander; }
private set
{
if (mParentExpander != value)
{
if (mParentExpander != null)
{
DetachParentExpander();
}
mParentExpander = value;
if (mParentExpander != null)
{
AttachParentExpander();
}
}
}
}
private void AttachParentExpander()
{
SetBinding(ParentExpanderLevelProperty, new Binding("Level") { Source = ParentExpander });
}
private void DetachParentExpander()
{
ClearValue(ParentExpanderLevelProperty);
}
#endregion
#endregion
#region Event handlers
private void DataGridGroupExpander_Loaded(object sender, System.Windows.RoutedEventArgs e)
{
ParentExpander = this.RecurseParents<DataGridGroupExpander>().Skip(1).Take(20).FirstOrDefault();
Owner = this.RecurseParents<DataGrid>().FirstOrDefault();
LoadGroupIsExpandedState();
}
#endregion
#region Methods
private void LoadGroupIsExpandedState()
{
if (!mSettingIsExpanded && Owner != null)
{
mSettingIsExpanded = true;
try
{
IsExpanded = Owner.LoadGroupIsExpandedState(Header);
}
finally
{
mSettingIsExpanded = false;
}
}
}
private void PersistGroupIsExpandedState()
{
if (!mSettingIsExpanded && Owner != null)
{
Owner.PersistGroupIsExpandedState(Header, IsExpanded);
}
}
private void SetFieldName()
{
var fieldName = "";
if (Owner != null && Owner.Items != null && Owner.Items.GroupDescriptions.Count > Level)
{
var groupDescription = Owner.Items.GroupDescriptions[Level] as PropertyGroupDescription;
if(groupDescription!=null)
{
fieldName = groupDescription.PropertyName;
}
}
SetValue(FieldNameKey, fieldName);
}
#endregion
#region Overrides
tected override void HeaderUpdated()
{
LoadGroupIsExpandedState();
}
tected override void IsExpandedUpdated()
{
PersistGroupIsExpandedState();
}
#endregion
#region Dependency Properties
#region ParentExpanderLevel
public int ParentExpanderLevel
{
get { return (int)GetValue(ParentExpanderLevelProperty); }
set { SetValue(ParentExpanderLevelProperty, value); }
}
public static readonly System.Windows.DependencyProperty ParentExpanderLevelProperty =
System.Windows.DependencyProperty.Register(
"ParentExpanderLevel",
typeof(int),
typeof(DataGridGroupExpander),
new System.Windows.PropertyMetadata(-1, OnParentExpanderLevelPropertyChanged));
private static void OnParentExpanderLevelPropertyChanged(System.Windows.DependencyObject sender, System.Windows.DependencyPropertyChangedEventArgs e)
{
var control = sender as DataGridGroupExpander;
if (control != null)
{
control.ParentExpanderLevelUpdated();
}
}
private void ParentExpanderLevelUpdated()
{
SetValue(LevelKey, ParentExpanderLevel + 1);
}
#endregion
#region Level
public int Level
{
get { return (int)GetValue(LevelProperty); }
}
internal static readonly DependencyPropertyKey LevelKey = DependencyProperty.RegisterReadOnly(
"Level",
typeof(int),
typeof(DataGridGroupExpander),
new System.Windows.PropertyMetadata(0, OnLevelPropertyChanged));
public static readonly DependencyProperty LevelProperty = LevelKey.DependencyProperty;
private static void OnLevelPropertyChanged(System.Windows.DependencyObject sender, System.Windows.DependencyPropertyChangedEventArgs e)
{
var control = sender as DataGridGroupExpander;
if (control != null)
{
control.LevelUpdated();
}
}
private void LevelUpdated()
{
SetFieldName();
}
#endregion
#region FieldName
public string FieldName
{
get { return (string)GetValue(FieldNameProperty); }
}
internal static readonly DependencyPropertyKey FieldNameKey = DependencyProperty.RegisterReadOnly(
"FieldName",
typeof(string),
typeof(DataGridGroupExpander),
new PropertyMetadata(null, OnFieldNamePropertyChanged));
public static readonly DependencyProperty FieldNameProperty = FieldNameKey.DependencyProperty;
private static void OnFieldNamePropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
{
var control = sender as DataGridGroupExpander;
if (control != null)
{
control.FieldNameUpdated();
}
}
private void FieldNameUpdated()
{
}
#endregion
#endregion
}
公共类DataGridGroupExpander:GroupExpander
{
#区域级变量
private bool mSettingIsExpanded=false;
#端区
#区域构造函数
公共DataGridGroupExpander()
{
设置绑定(标题属性,新绑定(“名称”);
加载+=DataGridGroupExpander\u加载;
}
#端区
#区域属性
#区域所有者
私有DataGrid mOwner=null;
公共数据网格所有者
{
获取{返回割草机;}
专用设备
{
如果(割草机!=值)
{
如果(割草机!=null)
{
所有者();
}
割草机=价值;
如果(割草机!=null)
{
AttachOwner();
}
}
}
}
私有无效附加值()
{
SetFieldName();
}
私有所有者()
{
}
#端区
#区域父扩展器
私有DataGridGroupExpander mParentExpander=null;
公共DataGridGroupExpander父扩展器
{
获取{return mParentExpander;}
专用设备
{
如果(mParentExpander!=值)
{
if(mParentExpander!=null)
{
分离父扩展器();
}
mParentExpander=值;
if(mParentExpander!=null)
{
AttachParentExpander();
}
}
}
}
私有void AttachParentExpander()
{
SetBinding(ParentExpanderLevel属性,新绑定(“级别”){Source=ParentExpander});
}
私有void DetachParentExpander()
{
ClearValue(ParentExpanderLevel属性);
}
#端区
#端区
#区域事件处理程序
已加载私有void DataGridGroupExpander_(对象发送方,System.Windows.RoutedEventArgs e)
{
ParentExpander=this.RecurseParents().Skip(1).Take(20).FirstOrDefault();
所有者=this.RecurseParents().FirstOrDefault();
LoadGroupIsExpandedState();
}
#端区
#区域方法
私有void LoadGroupIsExpandedState()
{
如果(!mSettingIsExpanded&&Owner!=null)
{
mSettingIsExpanded=true;
尝试
{
IsExpanded=Owner.LoadGroupIsExpandedState(标头);
}
最后
{
mSettingIsExpanded=false;
}
}
}
私有void PersistGroupIsExpandedState()
{
如果(!mSettingIsExpanded&&Owner!=null)
{
Owner.PersistGroupIsExpandedState(标头,IsExpanded);
}