c# - 带有分组项目的 ListView - 通过组标题复选框选择所有组成员

标签 c# wpf listview checkbox selected

我正在使用 C# 和 WPF,并且我有一个 ListView,它在第一列中包含带有 CheckBox 的项目。 ListView 的 ItemsSource 在代码中设置(不是通过绑定(bind)),并且包含具有属性“Name”、“Type”和“Selected”的类“Item”的实例。

public class Item : INotifyPropertyChanged
{
    private string _name;
    private bool _selected;
    private string _type;

    public string Name
    {
        get { return _name; }
        set
        {
            _name = value;
            this.OnPropertyChanged();
        }
    }

    public bool Selected
    {
        get { return _selected; }
        set
        {
            _selected = value;
            this.OnPropertyChanged();
        }
    }

    public string Type
    {
        get { return _type; }
        set
        {
            _type = value;
            this.OnPropertyChanged();
        }
    }

    protected virtual void OnPropertyChanged([CallerMemberName] string property = "")
    {
        if (this.PropertyChanged != null) this.PropertyChanged(this, new PropertyChangedEventArgs(property));
    }

    public event PropertyChangedEventHandler PropertyChanged;
}

ListView 的 View 设置为 GridView,第一列是一个绑定(bind)到 Selected 属性的复选框 - 例如,复选框表示被“选中”。

我正在向此 ListView 添加分组(按“类型”分组),GroupStyle 也包含一个 CheckBox。

        var lst = new List<Item>();
        lst.Add(new Item { Name = "A", Type = "1" });
        lst.Add(new Item { Name = "B", Type = "1" });
        lst.Add(new Item { Name = "C", Type = "1" });
        lst.Add(new Item { Name = "A", Type = "2" });
        lst.Add(new Item { Name = "B", Type = "2" });
        lst.Add(new Item { Name = "C", Type = "2" });

        listview.ItemsSource = lst;

        var view = CollectionViewSource.GetDefaultView(lst);
        view.GroupDescriptions.Add(new PropertyGroupDescription("Type"));

ListView 的 XAML 包含 GridView 和 GroupStyle:

    <ListView x:Name="listview">

        <!-- View -->
        <ListView.View>
            <GridView>
                <GridViewColumn Width="50">
                    <GridViewColumn.CellTemplate>
                        <DataTemplate DataType="cls:Item">
                            <CheckBox IsChecked="{Binding Selected, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
                        </DataTemplate>
                    </GridViewColumn.CellTemplate>
                </GridViewColumn>

                <GridViewColumn Width="300" Header="Name" DisplayMemberBinding="{Binding Name, UpdateSourceTrigger=PropertyChanged}"></GridViewColumn>

                <GridViewColumn Width="100" Header="Type" DisplayMemberBinding="{Binding Type}"></GridViewColumn>
            </GridView>
        </ListView.View>

        <!-- Group style -->
        <ListView.GroupStyle>
            <GroupStyle>
                <GroupStyle.ContainerStyle>
                    <Style TargetType="{x:Type GroupItem}">
                        <Setter Property="Template">
                            <Setter.Value>
                                <ControlTemplate>
                                    <Expander IsExpanded="True">
                                        <Expander.Header>
                                            <StackPanel Orientation="Horizontal">
                                                <CheckBox></CheckBox>
                                                <TextBlock Text="{Binding Name}" />
                                                <TextBlock Text="{Binding ItemCount, StringFormat='- {0} item(s)'}" />
                                            </StackPanel>
                                        </Expander.Header>
                                        <ItemsPresenter />
                                    </Expander>
                                </ControlTemplate>
                            </Setter.Value>
                        </Setter>
                    </Style>
                </GroupStyle.ContainerStyle>
            </GroupStyle>
        </ListView.GroupStyle>
    </ListView>

最后回答我的问题:我希望能够使用组标题 中的复选框来选择该特定组中的所有项目或不选择任何项目。例如:

Example

单击组标题复选框应选中该特定组中的所有项目(如果尚未选中)。再次单击它应该取消选择(取消选中)该组中的所有项目。如果用户手动选择或取消选择组中的某些项目,组标题复选框显示不确定状态会很好,但不选中也很好。

我不知道从哪里开始。我假设我需要绑定(bind)组 header 复选框的 IsChecked 属性,但我不知道将其绑定(bind)到什么,因为数据上下文将是某种不包含有关组的任何信息的 GroupDescriptor 东西,也不该组中有哪些项目(对吗??)。

我没有严格遵循 MVVM,所以我不用担心在绑定(bind)和我的 View 模型中完成这一切,我会很好地听取复选框的 Checked 事件并以某种方式在代码中找出哪些项目应该被检查。例如;如果我可以收听 Checked 事件并以某种方式提取组的类型,我将主要设置(我可以遍历整个列表并选择所有具有匹配组的组)。但是我什至没有看到这样做的方法;我可以在 Checked 事件(发件人)中获取 CheckBox,并且我可以循环到所有父控件,但是我在任何地方都看不到提取有关我正在分组的属性的信息的方法...

任何帮助都会很棒!

最佳答案

我想通了,我只需要 CheckBox 的 DataContext。这不是最漂亮的解决方案(肯定不是 MVVM),但它似乎工作正常。

只需将 Checked 和 Unchecked 事件处理程序添加到组样式中的复选框,将 DataContext 转换为包含项目的 CollectionViewGroup。

在嵌套分组的情况下,Items 集合包含 CollectionViewGroup 的另一个实例,因此当您找到另一个(嵌套)组时需要递归循环这些项目:

    private void OnGroupChecked(object sender, RoutedEventArgs e)
    {
        this.HandleGroupCheck((CheckBox)sender, true);
    }

    private void OnGroupUnchecked(object sender, RoutedEventArgs e)
    {
        this.HandleGroupCheck((CheckBox)sender, false);
    }

    private void HandleGroupCheck(CheckBox sender, bool check)
    {
        var group = (CollectionViewGroup) sender.DataContext;
        this.HandleGroupCheckRecursive(group, check);
    }

    private void HandleGroupCheckRecursive(CollectionViewGroup group, bool check)
    {
        foreach (var itemOrGroup in group.Items)
        {
            if (itemOrGroup is CollectionViewGroup)
            {
                // Found a nested group - recursively run this method again
                this.HandleGroupCheckRecursive(itemOrGroup as CollectionViewGroup, check);
            }
            else if (itemOrGroup is Item)
            {
                var item = (Item)itemOrGroup;
                item.Selected = check;
            }
        }
    }

现在我还需要弄清楚如何响应选中items并更改相应组中的复选框。

关于c# - 带有分组项目的 ListView - 通过组标题复选框选择所有组成员,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24148593/

相关文章:

c# - 使用 GridViewColumn 创建 ListView

c# - 该进程无法访问文件 'C:\file.txt',因为它正被另一个进程使用

c# - 如何在 C# 4.0 WPF webbrowser 应用程序上单击按钮或提交表单或单击 url 或单击图像

c# - 以编程方式调用 ASMX 中的所有操作

c# - 检查 Windows 应用程序的更新功能

c# - Entity Framework 中的僵尸对象

wpf - 如何使 WPF 输入控件在触摸屏上获得焦点时显示虚拟键盘

android - 自动更改ListView的背景图片

java - 运行时更新 AlertDialog 的 ListView 内容

c# - 从一个 API 调用返回 TitleCase JSON,其余部分使用驼峰命名法