防止DataGrid组在排序时崩溃?

时间:2012-03-28 16:27:14

标签: wpf datagrid

我有一个WPF数据网格,我在其中按特定属性对数据进行分组。 所有标准的东西。 但是,当我单击其中一个列标题以按该列排序时,它会折叠所有组。我想尽可能防止这种情况发生。 我可以捕获DataGrid的Sorting事件,如果我尝试将组的Expander设置为“IsExpanded”,它就没有效果,因为似乎IsExpanded已经为真,即使它没有显示为展开。

它似乎是标准行为,而不仅仅是我的数据,所以任何人都可以给出如何实现这一点的任何例子都会很棒。

我为数据网格获得的xaml是这样的:

<DataGrid ItemsSource="{Binding Items}" x:Name="dataGrid">
    <DataGrid.GroupStyle>
        <GroupStyle>
            <GroupStyle.ContainerStyle>
                <Style TargetType="GroupItem">
                    <Setter Property="Template">
                        <Setter.Value>
                            <ControlTemplate>
                                <Expander>
                                    <Expander.Header>
                                        <TextBlock>
                                    <TextBlock.Text>
                                        <MultiBinding StringFormat="{}{0} ({1} Items)">
                                            <MultiBinding.Bindings>
                                                <Binding Path="Name"/>
                                                <Binding Path="ItemCount"/>
                                            </MultiBinding.Bindings>
                                        </MultiBinding>
                                    </TextBlock.Text>
                                        </TextBlock>
                                    </Expander.Header>
                                    <ItemsPresenter/>
                                </Expander>
                            </ControlTemplate>
                        </Setter.Value>
                    </Setter>
                </Style>
            </GroupStyle.ContainerStyle>
        </GroupStyle>
    </DataGrid.GroupStyle>
</DataGrid>

由于

2 个答案:

答案 0 :(得分:4)

我遇到了同样的问题,这给我带来了很多麻烦。最后,我来到这里,可能不是最优雅,但工作的解决方案(我必须使它与多分组一起工作,所以你将免费获得该功能:)。 主要思想是在排序发生之前记住每个扩展器的状态,并在排序完成后恢复它。为了达到这个目的,我已经:

  1. 在每个手动扩展或折叠记录其状态(实际上我只保留扩展扩展器的状态)。作为扩展器标识符,我使用从绑定到扩展器的元素生成的id)

  2. 评估扩展器的IsExpanded属性时使用的转换器检查当前扩展器状态是否在已保存状态列表中,并相应地返回IsExpanded值。

  3. 在GroupStyle中扩展:

        <Expander x:Name="exp" Expanded="exp_Expanded" Collapsed="exp_Collapsed" >
            <Expander.IsExpanded>
                <MultiBinding Converter="{StaticResource ResourceKey=expanderStateConverter}" Mode="OneWay" >
                    <Binding Mode="OneWay"/>
                    <Binding RelativeSource="{RelativeSource FindAncestor, AncestorType={x:Type Window}}" Path="ExpandersStates" />
                </MultiBinding>
            </Expander.IsExpanded>
        <!-- ... the rest of the boring expander code -->
        </Expander>
    

    如果需要,请将AncestorType窗口部分替换为您的控件类型...

    视图中的代码:

        public List<string> ExpandersStates {get; set; }
        private void exp_Expanded(object sender, RoutedEventArgs e)
        {
            ExpandCollapseExpander(sender as Expander, e, true);
        }
    
        private void exp_Collapsed(object sender, RoutedEventArgs e)
        {
            ExpandCollapseExpander(sender as Expander, e, false);
        }
    
        private void ExpandCollapseExpander(Expander exp, RoutedEventArgs e, bool doExpand)
        {
            CollectionViewGroup collectionViewGroup = exp.DataContext as CollectionViewGroup;
            if (collectionViewGroup == null)
            {
                return;
            }
            string viewGroupId = FormViewGroupIdentifier(collectionViewGroup, null);
            if (doExpand)
            {
                if (!ExpandersStates.Contains(viewGroupId))
                {
                    ExpandersStates.Add(viewGroupId);
                }
            }
            else
            {
                ExpandersStates.Remove(viewGroupId);
            }
            e.Handled = true;
        }
    
        public static string FormViewGroupIdentifier(CollectionViewGroup collectionViewGroup, string sufix)
        {
            string formViewGroupIdentifier = collectionViewGroup.Name + sufix;
            CollectionViewGroup parentgroup = GetParent(collectionViewGroup);
            if (parentgroup == null)
            {
                return formViewGroupIdentifier;
            }
            else
            {
                return FormViewGroupIdentifier(parentgroup, "putHereSomeDelimiterWhichWillNeverOccurInYourGroupingProperty" + formViewGroupIdentifier);
            }
        }
    
        private static CollectionViewGroup GetParent(CollectionViewGroup collectionViewGroup)
        {
            Type type = collectionViewGroup.GetType();
            if (type.Name == "CollectionViewGroupRoot")
            {//if we are at the root level return null as there is no parent
                return null;
            }
    
            CollectionViewGroup parentgroup
                = type.GetProperty("Parent", System.Reflection.BindingFlags.GetProperty | System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic)
                .GetValue(collectionViewGroup, null) as CollectionViewGroup;
            return parentgroup;
        }
    

    转换器:

    public class ExpanderStateConverter : IMultiValueConverter
    {
        public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
        {
            CollectionViewGroup collectionViewGroup = values[0] as CollectionViewGroup;
            List<string> expandersStates = values[1] as List<string>;
            if (!expandersStates.Any())
            {//prevent forming group identifier to speed up process as there are no expanded expanders anyway
                return false;
            }
    
            string groupId = MainWindow.FormViewGroupIdentifier(collectionViewGroup, null);
            bool contains = expandersStates.Contains(groupId);
            return contains;
        }
    
        public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
        {
            return new object[2];
        }
    }
    

    我知道在这里使用任意分隔符生成扩展器的标识符并不是最好的做法,我愿意接受如何改进它的建议。

    此处提供完整代码:ExpandersForSO2

答案 1 :(得分:0)

您是否可以通过添加:<Expander>

来简单地更改<Expander IsExpanded="True">节点