1

我有一个带有 ListCollectionView 作为数据源的 ItemControl。ItemControl 使用 Expander 控件对项目进行分组。当我执行 ListCollectionView.Refresh() 时,展开的 Expander 控件会折叠。如何使扩展的控件保持扩展状态?

<ItemsControl HorizontalAlignment="Stretch" ItemsSource="{Binding}" Name="ItemsControl1">
        <ItemsControl.Resources>
            <DataTemplate DataType="{x:Type GroupingWithExpander:DataItem}">
                <TextBlock Text="{Binding Text}" />
            </DataTemplate>
        </ItemsControl.Resources>
        <ItemsControl.GroupStyle>
            <GroupStyle>
                <GroupStyle.ContainerStyle>
                    <Style TargetType="GroupItem">
                        <Setter Property="Template">
                            <Setter.Value>
                                <ControlTemplate TargetType="GroupItem">
                                    <Expander BorderThickness="1" BorderBrush="Gray" IsExpanded="{Binding IsExpanded}">
                                        <Expander.Resources>
                                            <GroupingWithExpander:DataGroupToNameConverter x:Key="DataGroupToNameConverter" />
                                        </Expander.Resources>
                                        <Expander.Header>
                                            <TextBlock Text="{Binding Name, Converter={StaticResource DataGroupToNameConverter}}" />
                                        </Expander.Header>
                                        <StackPanel Orientation="Vertical">
                                            <ItemsPresenter Margin="5 0" />
                                        </StackPanel>
                                    </Expander>
                                </ControlTemplate>
                            </Setter.Value>
                        </Setter>
                    </Style>
                </GroupStyle.ContainerStyle>
            </GroupStyle>
        </ItemsControl.GroupStyle>
        <ItemsControl.ItemsPanel>
            <ItemsPanelTemplate>
                <VirtualizingStackPanel Orientation="Vertical" IsItemsHost="True" />
            </ItemsPanelTemplate>
        </ItemsControl.ItemsPanel>
    </ItemsControl>
    <TextBox Name="TextBox1" />
    <Button Click="Button_Click">
        <Button.Content>
            <TextBlock Text="do something" />
        </Button.Content>
    </Button>



 public partial class MainWindow : Window{
public MainWindow()
            {
                InitializeComponent();
                var group1 = new DataGroup {IsExpanded = false, Name = "group #1"};
                var group2 = new DataGroup {IsExpanded = true, Name = "group #2"};
                const int itemsCount = 6;
                DataItem[] dataItems = new DataItem[itemsCount];
                for (int i = 0; i < itemsCount; i++)
                {
                    DataItem item = new DataItem
                                        {
                                            Group = (i%2 == 0 ? group1 : group2),
                                            Text = System.IO.Path.GetRandomFileName()
                                        };
                    dataItems[i] = item;
                }
                ListCollectionView v = new ListCollectionView(dataItems);            
                v.GroupDescriptions.Add(new PropertyGroupDescription("Group"));
                v.Filter = FilterDataItem;
                this.DataContext = v;            
            }

            private bool FilterDataItem(object o)
            {
                DataItem item = o as DataItem;
                return item.Contains(this.TextBox1.Text);            
            }

            private void Button_Click(object sender, RoutedEventArgs e)
            {
                ListCollectionView v = (ListCollectionView) this.DataContext;
                v.Refresh();
            }
    }

    class DataGroup : IEquatable<DataGroup>, INotifyPropertyChanged
{
    public string Name { get; set; }

    private bool _isExpanded;
    public bool IsExpanded
    {
        get { return _isExpanded; }
        set 
        { 
            _isExpanded = value; 
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs("IsExpanded"));
        }
    }

    public bool Equals(DataGroup other)
    {
        return other != null && this.Name == other.Name;
    }

    public event PropertyChangedEventHandler PropertyChanged;
}

    class DataItem
{
    public string Text { get; set; }
    public DataGroup Group { get; set; }

    public virtual bool Contains(string filterString)
    {
        return Text != null && (string.IsNullOrEmpty(filterString) || Text.Contains(filterString));
    }
}




    class DataGroupToNameConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        if (!(value is DataGroup)) throw new ArgumentException("type DataGroup is expected", "value");
        DataGroup g = (DataGroup) value;
        return g.Name;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}
4

1 回答 1

1

您非常接近可行的解决方案。关键是要知道DataContext组模板中的控件将是一个CollectionViewGroup(实际上是它的后代,因为CollectionViewGroup是抽象的)。当框架绑定到应用了分组的​​数据源时,框架会为您创建这些组。

CollectionViewGroup有一个名为 的属性Items,它是一个集合,其中包含属于由 表示的组的项CollectionViewGroup。由于每个组都将至少有一个成员,因此您可以使用第一个成员Items来访问DataGroup,例如Items[0].Group.IsExpanded,但还有更简单的方法。

CollectionViewGroup 还有一个有点误导的属性,叫做Name. 乍一看,您可能会认为它是string包含组名的 a,但实际上它是object对您告诉数据源分组依据的任何实例的引用。

在您的示例中,您已告诉它按Group属性分组,即 a DataGroup,因此Name实际上将指向该DataGroup组的实例。

DataGroup因此,您可以通过在绑定中使用虚线路径来获取 的属性,即:

<Expander IsExpanded="{Binding Name.IsExpanded}">
    <Expander.Header>
        <TextBlock Text="{Binding Name.Name}" />
    </Expander.Header>
    <StackPanel Orientation="Vertical">
        <ItemsPresenter Margin="5 0" />
    </StackPanel>
</Expander>

我进行了这些更改,您的示例现在可以正常工作。您也不再需要值转换器。

我还更改了您的按钮单击事件,以证明绑定在两个方向上都有效(当您单击按钮时,它会切换每个组的展开状态):

private void Button_Click(object sender, RoutedEventArgs e)
{
    ListCollectionView v = (ListCollectionView)this.DataContext;

    var groups = new List<DataGroup>();
    for (int i = 0; i < v.Count; i++)
    {
        var item = v.GetItemAt(i) as DataItem;
        if (item != null)
        {
            if (!groups.Contains(item.Group))
            {
                groups.Add(item.Group);
            }
        }
    }

    foreach (var group in groups)
    {
        group.IsExpanded = !group.IsExpanded;
    }

    v.Refresh();
}

我刚刚使用分组的 ComboBox 进行了类似的练习,所以我回答这个问题是希望虽然它可能不再与您相关,但它可以帮助处于类似困境的其他人。

于 2013-05-24T17:07:05.717 回答