Click here to Skip to main content
15,868,016 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
I like to expand/collapse a WinForm list. Without set anything to subtitle and footer properties, it works.
However if I once set any text to subtitle or footer, that never disappear from GUI.
1) By default my groups are collapsed, only headers are visible, which is my intention. Of course by default there is no content assigned to footer and subtitle properties.
2) On the GUI collapse/expand controls works fine.
3) On some event (for example a button click) I assign subtitle/footer content.
4) Now the assigned tetx visible on GUI
5) On some event I clear the text from subtitle/footer properties as visible in sample code
6) Now I can't get rid of the content from subtitle/footer. No matters how I try, set those properties to null or empty string. The last set text remains and laugh at me. By the way I can change the content to toher string. But I can't set to "" or null.

What I have tried:

C#
if (listView1.Groups[0].CollapsedState == ListViewGroupCollapsedState.Collapsed)
{
    listView1.Groups[0].Subtitle = "firg rulez";
    listView1.Groups[0].CollapsedState = ListViewGroupCollapsedState.Expanded;
}
else
{
    listView1.Groups[0].Subtitle = string.Empty;
    listView1.Groups[0].CollapsedState = ListViewGroupCollapsedState.Collapsed;
}
Posted
Updated 28-Dec-22 7:19am

1 solution

I did a quick google: winform listview group collapse - Google Search[^] and the first search result: ListView hide or collapse selected group [solution] - StackOverflow[^] pointed to an article right here on Code Project that does exactly what you want: Add Group Collapse Behavior on a Listview Control[^]

UPDATE
It's been a long time since I've spent any real-time WinForms as I work in WPF when doing Windows apps. In WPF, this is possible to do using templates. I was curious as to if it was possible in WinForms using the new feature. So I fired up VS and wrote a mock app using the ListView.

What I learned, after experimenting, then digging into the ListViewGroup control source code is that the SubTitle and Footer properties of the ListViewGroup are always shown if set. (ref: SubTitle Property[^] & Footer Property[^] ). It is a limitation of Microsoft's implementation. You can read more about the discussion of the request and implementation of this feature here: Add Collapse Support to ListViewGroup · Issue #3067 · dotnet/winforms · GitHub[^]

The only option at this stage, without further, digging into the source code, is to set the values to a " " (space), not an empty string or default value. This will leave a blank row on the control.

Alternatively, the other option is to set the SubTitle/Footer with updated information for when the CollapsedState changes in the GroupCollapsedStateChanged event.

Otherwise, look at the initial link above and see if there is an "old school" way of doing what you want.

UPDATE #2
Here is my test code:
C#
public partial class Form1 : Form
{
    private Random random = new();

    private List<Person> friends = new();

    private List<string> groups = new()
    {
        "Enemies",
        "People That I Know",
        "Friends",
        "Close Friends",
        "Best Friends"
    };

    public Form1()
    {
        InitializeComponent();
        InitData();
        InitListBox();
        InitListView();
    }

    private void InitListBox()
    {
        listBox1.Dock = DockStyle.Bottom;
        listBox1.Height = 200;
    }

    private void InitData()
    {
        for (int i = 0; i < 100; i++)
            friends.Add(new Person($"Firstname {i}", $"LastName {i}", groups[random.Next(0, 5)]));
    }

    private void InitListView()
    {
        listView1.View = View.Details;
        listView1.Dock = DockStyle.Fill;
        listView1.FullRowSelect = true;

        listView1.GroupCollapsedStateChanged += ListView1_GroupCollapsedStateChanged;

        listView1.Columns.Add("FirstName", 150);
        listView1.Columns.Add("LastName", 150);
        listView1.Columns.Add("Group", 100);

        foreach (string group in groups)
        {
            ListViewGroup item = new(group)
            {
                CollapsedState = ListViewGroupCollapsedState.Expanded,
                Subtitle = $"Subtitle for {group}",
                Footer = $"Footer for {group}"
            };

            listView1.Groups.Add(item);
        }

        foreach (Person friend in friends)
        {
            ListViewItem item = new(new string[]
            {
                friend.FirstName, 
                friend.LastName, 
                friend.Group
            });
            item.Group = listView1.Groups[groups.IndexOf(friend.Group)];
            listView1.Items.Add(item);
        }
    }

    private void ListView1_GroupCollapsedStateChanged(object? sender, ListViewGroupEventArgs e)
    {
        Debug.WriteLine("ListView1_GroupCollapsedStateChanged");

        ListViewGroup group = listView1.Groups[e.GroupIndex];
        ListViewGroupCollapsedState state = group.CollapsedState;

        group.Footer = null;

        listView1.call("UpdateGroupNative", group);
        listView1.call("UpdateGroupView");

       listBox1.Items.Insert(0, $"{listBox1.Items.Count + 1}:  Group[{e.GroupIndex}] {group.Name} is now {state}");
    }
}

public record Person(string FirstName, string LastName, string Group);

static class ObjectExtensions
{
    public static object? call(this object obj, string methodName, params object[]? args)
    {
        MethodInfo? mi = obj.GetType ().GetMethod (methodName, System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance );

        return mi != null
            ? mi.Invoke (obj, args)
            : null;
    }
}
 
Share this answer
 
v4
Comments
Liktor Janos 29-Dec-22 14:28pm    
Thanks Graeme_Grant, about that article, I've read it. That is a 14 years old article, and discuss about the missing group collapse of ListView. Now there is collapse function already in ListView. The collapse function of list view is almost do as I want... The culprit is I can't set Footer and Subtitle properties to an empty string. By the way, you (and the article) give me an idea about override the footer and subtitle setter. Maybe there is a crazy check about the input string. Let's see.
Liktor Janos 30-Dec-22 4:49am    
Whoa! What a complete solution :) Thanks. I also thought that statechange event trick, however I have no time to experiment with that. Ok, now you pushed me to the right direction :)
Graeme_Grant 30-Dec-22 7:40am    
You are most welcome.

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900