我在 FastObjectListView (2.9.1) 中错误地使用了 ShowGroups 还是错误?

Am I incorrectly using ShowGroups in FastObjectListView (2.9.1) or is it a bug?

我在 v2.9.1 中遇到了 FastObjectListView 的问题。

作为一个最小的测试示例:我有一个 FastObjectListView,我以编程方式向其添加了两个 OLVColumn objects。当第一列不可分组并且我打开 ShowGroups 时,我在 FastListGroupingStrategy.GetGroup.

中得到一个 Null Ref 异常

这是因为 indexToGroupMap 从未在 FastListGroupingStrategy.GetGroup 中实例化,因为 ObjectListView.BuildGroups 中的检查跳过了 non-Groupable 列的组构建。根据此代码片段:

 if (parms.GroupByColumn != null)
     args.Canceled = !parms.GroupByColumn.Groupable;
 this.OnBeforeCreatingGroups(args);
 if (args.Canceled)
    return;

那么问题来了,我是不是在滥用控件?是否应该由我根据当前列是否可排序来打开和关闭 ShowGroups?

还是bug? (如果 this.OLVGroups == null, 可能 通过将 VirtualObjectListView.GetDisplayOrderOfItemIndex 更改为 return itemIndex 来修复)?

示例代码

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }

    private void Form1_Load(object sender, EventArgs e)
    {
        InitColumns();
        fastObjectListView1.ShowGroups = true;
        modelObjects_.Add(new ModelObject { Name = "Anne", Age = 20 });
        modelObjects_.Add(new ModelObject { Name = "Beth", Age = 20 });
        modelObjects_.Add(new ModelObject { Name = "Claire", Age = 32 });
        modelObjects_.Add(new ModelObject { Name = "Della", Age = 31 });
        modelObjects_.Add(new ModelObject { Name = "Ellie", Age = 20 });
        modelObjects_.Add(new ModelObject { Name = "Fiona", Age = 31 });
        fastObjectListView1.Objects = modelObjects_;
    }


    void InitColumns()
    {
        {
            OLVColumn col = new OLVColumn();
            col.Name = "NameColumn";
            col.IsVisible = true;
            col.AspectGetter = o => CastToModel(o).Name;
            col.AspectToStringConverter = a => a.ToString();
            col.Groupable = false;
            col.IsEditable = false;
            col.Text = "Name";
            col.Width = 150;
            fastObjectListView1.AllColumns.Add(col);
        }
        {
            OLVColumn col = new OLVColumn();
            col.Name = "AgeColumn";
            col.IsVisible = true;
            col.AspectGetter = o => CastToModel(o).Age;
            col.AspectToStringConverter = a => a.ToString();
            col.Groupable = true;
            //col.ImageGetter = 
            col.IsEditable = false;
            col.Text = "Age";
            col.Width = 50;
            fastObjectListView1.AllColumns.Add(col);
        }
        fastObjectListView1.RebuildColumns();
    }

    ModelObject CastToModel(object o)
    {
        return (ModelObject)o;
    }  

List<ModelObject> modelObjects_ = new List<ModelObject>();
}

public class ModelObject
{
    public string Name;
    public int Age;
}

还有一个副作用(出乎我意料):

Sorting/grouping 通过单击列 header 在可分组列上工作正常

然后 sorting/grouping 在 non-Groupable 列上保留先前的分组。

使用 col.Groupable = true; 告诉 ListView“是否可以按列分组”。

但是第一列是一个特殊的列,其中一个原因是因为它用于组,至少最初是这样。这意味着您需要通过设置以下内容来覆盖它;

col.Name = "AgeColumn";
...
fastObjectListView1.AlwaysGroupByColumn = col;

但是,这会导致您无法按任何其他列进行分组。在您的示例中不是问题,但如果您扩展模型,这可能是个问题。

所以另一种解决方案是改用 GroupKeyGetter

在这里,您需要对第一列进行一些不同的定义,并仅为该列设置 GroupKeyGetter。

//Define your first column at the class level;
private OLVColumn colName;

//Define InitColumns
void InitColumns()
{
    colName = new OLVColumn();
    colName.Name = "NameColumn";
    colName.Groupable = true;  //Make this groupable again, as we effectively override it.
    ...
    //Rest same as before
}

//In form_load
private void Form1_Load(object sender, EventArgs e)
{
    InitColumns();            
    ...
    //define your objects, same as before

    this.colName.GroupKeyGetter = delegate (object rowObject)
    {
        ModelObject item = (ModelObject)rowObject;
        return item.Age;
    };

    fastObjectListView1.ShowGroups = true;
    fastObjectListView1.Objects = modelObjects_;
}

这样做的好处是它“覆盖”了第一列的分组方式(有效地使用与第二列相同的方式),但仍然允许您毫无问题地按所有其他列分组。

There is another side effects (unexpected by me):

Sorting/grouping on a Groupable column via clicking column header works ok

Then sorting/grouping on a non-Groupable column leaves previous grouping in place.

这是预期的行为。这就是“Groupable”属性的意义所在。