Click here to Skip to main content
15,893,266 members
Articles / Desktop Programming / Windows Forms

Scrolling to a Group with a ListView

Rate me:
Please Sign up or sign in to vote.
4.00/5 (1 vote)
4 Jul 2008BSD3 min read 55.6K   1.1K   31   3
Add the functionality to scroll to a group in a ListView

Introduction

I had some data that I needed to display in a listview. The data was represented by images, and sorted into groups. Since there could be dozens (hundreds?) of images, I thought it would be useful to be able to jump to any group using buttons (1 button per group). Unfortunately, scrolling to a group is not something that the .NET ListView control supports out of the box.

listViewScroll_screenshot.png

Above is a screenshot of 4 buttons that scroll the listview to 4 groups.

Background

The first time I tried to implement scroll-to-a-group, I used the EnsureVisible method on the first list item in a group. This works, but it's not great. The problem is that the control will scroll just enough to make the item visible, and that could mean making it visible at the top or bottom of the control. If you have many 16x16 icons, it takes several seconds to find the item that you just EnsureVisible'd. With EnsureVisible, nothing will happen if the item is already visible. Also, EnsureVisible can only be applied to ListViewItems, not to ListViewGroups (but Groups is what I wanted). The other method that was suggested to me was to use the TopItem method. This cannot be used if the ListView's view mode is LargeIcon or SmallIcon or Tile (I was using LargeIcon), so TopItem was out of the question.

Using the Code

Usage is simple: Add the AdvancedListView class to your project. When you want to scroll to a group, pass the group's name or index to AdvancedListView.ScrollToGroup() and you will see your ListView scroll so that the group header is right at the top of the control.

C#
myListView.ScrollToGroup(myListViewItem.Group.Name);

Points of Interest

The main trick to getting this to work was realizing that the .NET Framework just couldn't scroll to a group. I needed to use the SendMessage function to send a LVM_SCROLL message to the ListView control. In discussion forums, it had often been suggested to use WM_VSCROLL, but this did NOT work. Using WM_VSCROLL, I was only able to move the scrollbar, but could not scroll the contents. The LVM_SCROLL message allows the listview contents to be scrolled as well.

This message takes two values, which are used to determine how much to scroll the listview by, relative to its CURRENT scroll position. The problem with this is that the position of the group is an absolute position, based on the position of the first item in the group:

C#
myListViewGroup.Items[0].Position.Y - 30

To get the correct amount to scroll by, we need to first get the current scroll position, using the API function GetScrollInfo:

C#
int prevScrollPos = 0;
SCROLLINFO currentInfo = new SCROLLINFO();
currentInfo.cbSize = Marshal.SizeOf(currentInfo);
currentInfo.fMask = (int)ScrollInfoMask.SIF_ALL;

GetScrollInfo(this.Handle, (int)ScrollBarDirection.SB_VERT, ref currentInfo)
    prevScrollPos = currentInfo.nPos;

//The LVM_SCROLL message will take a delta-x and delta-y which tell the list view how 
//much to scroll, relative to the current scroll positions. We are given the scroll
//position as an absolute position, so some adjustments are necessary:
scrollPos -= prevScrollPos;

As it turns out, there are MANY ListView messages. You can see all of them
here. I used a very simple structure for the one message that I needed:

C#
private enum ListViewMessages : int  
{   
    LVM_FIRST = 0x1000,   
    LVM_SCROLL = (LVM_FIRST + 20)   
}

Using this message to scroll can be done like this (although my code doesn't actually have a scrollAmtX because I was not interested in horizontal scrolling):

C#
SendMessage(listViewHandle, (uint)ListViewMessages.LVM_SCROLL, 
	(IntPtr)scrollAmtX, (IntPtr)scrollAmtY);

History

  • July 5 2008: Added a screenshot, added a bit more explanation

License

This article, along with any associated source code and files, is licensed under The BSD License


Written By
Web Developer
Canada Canada
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
QuestionHow to scroll to a group using EnsureVisible Pin
micbarton1-Sep-10 2:20
micbarton1-Sep-10 2:20 
QuestionImages? Pin
Jaime Olivares5-Jul-08 4:23
Jaime Olivares5-Jul-08 4:23 
AnswerRe: Images? Pin
The_Mega_ZZTer5-Jul-08 5:16
The_Mega_ZZTer5-Jul-08 5:16 
An explanation about how you used the scroll message to get the group scrolled would also be appreciated. Right now your article centers on how to scroll the ListView to an arbitrary X/Y position, which, although possibly useful, isn't the full solution to your problem.

Did you figure out the first item in the group, get the position of the item, and subtract a vertical constant for the group header? Or is there a API call to get the position of a group header?

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.