WPF ListView按2列分组,但只显示1个组头

时间:2013-10-07 10:08:35

标签: wpf listview grouping

ListView显示以下类的集合:

public class Employee
{
    private string _department;
    private string _manager;
    private string _name;
    private string _address;

    public string Department
    {
        get { return _department; }
    }
    public string Manager
    {
        get { return _manager; }
    }
    public string Name
    {
        get { return _name; }
    }
    public string Address
    {
        get { return _address; }
    }
}

部门和经理之间存在一对一的关系,因此具有相同部门的任何两行也将具有相同的经理。

我想按部门/经理进行分组,组头显示“部门(经理)”。

我的CollectionViewSource看起来像

    <CollectionViewSource x:Key="cvsEmployees" Source="{Binding Employees}">
        <CollectionViewSource.GroupDescriptions>
            <PropertyGroupDescription PropertyName="Department" />
            <PropertyGroupDescription PropertyName="Manager" />
        </CollectionViewSource.GroupDescriptions>
    </CollectionViewSource>

计划是不显示第一级标题(Department)并以某种方式从第二级标题绑定到Department(第1级)和Manager(第2级)。

3个问题:

  1. 为了避免显示第一级标题,我在groupstyle中有一个空数据模板:

    <GroupStyle>
        <GroupStyle.HeaderTemplate>
           <DataTemplate>
           </DataTemplate>
        </GroupStyle.HeaderTemplate>
    </GroupStyle>
    

    这看起来非常笨重。有没有更优雅的方法来跳过组头?

  2. 如何从第二级标题(Manager)绑定到第一个分组级别属性(部门)以获得所需的“部门(经理)”?

  3. 有没有比创建2个分组级别更好的方法?

  4. 由于

2 个答案:

答案 0 :(得分:3)

解决了上面的问题2的主要障碍:如何从组头绑定到不是分组属性的属性。

解决方案是将数据上下文更改为:{Binding Items}。然后可以使用ItemSource属性

<GroupStyle>
    <GroupStyle.HeaderTemplate>
        <DataTemplate>
            <StackPanel Orientation="Horizontal" Margin="0,10,0,3" DataContext="{Binding Items}" >
                <TextBlock Text="{Binding Path=Department}" FontWeight="Bold" Margin="3"/>
                <TextBlock Text="{Binding Path=Manager, StringFormat='({0})'}" Margin="3"/>
            </StackPanel>
        </DataTemplate>
    </GroupStyle.HeaderTemplate>
</GroupStyle>

答案 1 :(得分:2)

我会创建另一个模型部分,它代表您需要发生的双重分组:

模型类:

public class EmployeeModel {

        private readonly Employee _Employee;

        public DepartmentManager ManagementInfo { get; private set; }

        public string Name {
            get { return _Employee.Name; }
        }
        public string Address {
            get { return _Employee.Address; }
        }

        public EmployeeModel(Employee employee) {
            this._Employee = employee;
            this.ManagementInfo = new DepartmentManager(employee.Department, employee.Manager);
        }
    }

    public class DepartmentManager {

        public string Department { get; private set; }
        public string Manager { get; private set; }

        public DepartmentManager(string dept, string manager) {
            this.Department = dept;
            this.Manager= manager;
        }

        public override bool Equals(object obj) {
            var model = obj as DepartmentManager;
            if(null == model)
                return false;

            return Department.Equals(model.Department, StringComparison.InvariantCultureIgnoreCase) && 
                Manager.Equals(model.Manager, StringComparison.InvariantCultureIgnoreCase);
        }
    }

XAML:

    <CollectionViewSource x:Key="cvsEmpsModel" Source="{Binding EmployeesModel}">
        <CollectionViewSource.GroupDescriptions>
            <PropertyGroupDescription PropertyName="ManagementInfo" />
        </CollectionViewSource.GroupDescriptions>
    </CollectionViewSource>

    <DataTemplate DataType="{x:Type models:EmployeeModel}">
        <StackPanel Orientation="Horizontal">
            <TextBlock Text="{Binding Name}" />
            <TextBlock Text="{Binding Address}" />
        </StackPanel>
    </DataTemplate>

...
    <ListView ItemsSource="{Binding Source={StaticResource cvsEmpsModel}}">
            <ListView.GroupStyle>
                <GroupStyle>
                    <GroupStyle.HeaderTemplate>
                        <DataTemplate>
                            <StackPanel Orientation="Horizontal" Margin="0,10,0,3" DataContext="{Binding Items}">
                                <TextBlock Text="{Binding Path=ManagementInfo.Manager}" FontWeight="Bold" Margin="3" />
                                <TextBlock Text="{Binding Path=ManagementInfo.Department, StringFormat='({0})'}" Margin="3" />
                            </StackPanel>
                        </DataTemplate>
                    </GroupStyle.HeaderTemplate>
                </GroupStyle>
            </ListView.GroupStyle>
        </ListView>

然后在你的Window / ViewModel中:

this.EmployeesModel = new ObservableCollection<EmployeeModel>(MyListOfEmployersFromDB.Select(e => new EmployeeModel(e)));

请注意,我已在Equals课程中覆盖DepartmentManager,但未覆盖GetHashCode,理想情况下,您应该对其进行自定义实施。我必须重写equals,以便分组视图源能够正确地对相同的条目进行分组。您可以摆脱这种需求,为集合外的相同Employees构建DepartmentManager,并将它们传递到EmployeeModel ctr。