如何根据WPF中的组名折叠/展开多个扩展控件?

如何根据WPF中的组名折叠/展开多个扩展控件?,wpf,expander,collectionviewsource,groupstyle,Wpf,Expander,Collectionviewsource,Groupstyle,我想要实现的是:折叠或展开组样式中共享相同组名的所有扩展器 我们有一个列表框和嵌套在其中的另一个列表框来显示子项。子项ItemsSource绑定到附加了组描述的CollectionView 组项目模板非常简单: <Expander IsExpanded="{Binding Path=WHAT_TO_DO, Mode=TwoWay}"> <Expander.Header> <TextBlock T

我想要实现的是:折叠或展开组样式中共享相同组名的所有扩展器

我们有一个列表框和嵌套在其中的另一个列表框来显示子项。子项ItemsSource绑定到附加了组描述的CollectionView

组项目模板非常简单:

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