Tue, December 19, 2006, 10:39 AM under
Windows |
Vista
Open your windows explorer on Vista and click around the “Folders” section in the left (below your “Favorite Links”). Do you observe two things that were not there pre-Vista? That is right, the treeview has no horizontal scrollbar at the bottom and scrolling happens for you automatically as you select nodes that are not fully visible and as you mouse over around. Resize that area to be smaller if you are not observing this effect. Now do you notice the effect? Cool :)
It turns out that you can make any TreeView behave like that, if you want to. The clue for me was accidentally coming across the
TVS_EX_AUTOHSCROLL constant.
<this took me longer than what it should>
I must admit that it took me a while to get this working. First when my simple mind encountered
extended style it thought: “I know those and I know how to change them for managed controls”. So I overrode
CreateParams and changed the
ExStyle property but that had no effect. I then assumed that the reason it wasn’t working was because I had to send it the
TVM_SETAUTOSCROLLINFO message so I played with that, messing with various values since the documentation gives no clue to sensible starters and then gave up when I was still not observing the results. BTW, spy++ wasn’t helping much since prolongued use caused the machine to freeze and rebooting added to my overall frustration. Eventually a virtual slap made me realise that I need to send a custom message for the extended
treeview style (not
window style). Digging around I found the
TVM_SETEXTENDEDSTYLE message and tried sending that. Another round of trials and errors with no luck; only after opening
commctrl.h I could work out what params to send and in what order. I knew the messages were reaching the TreeView as I started using my own TreeView and overriding
DefWndProc with debug statements to make sure that the message wasn't been swallowed by the managed implementation. A complete red herring came out of nowhere questioning whether I was using v6 of comctl32.dll (of course I was, my commandlinkbutton etc worked fine, but to be positive, I manifested the assembly to make sure that was indeed the case). At this point, you can imagine that I was hacking at this API for quite a while, editing code and then running the project. At some point I got lazy and my test of whether it worked or not was: Does an hscrollbar appear in the treeview. Well it turns out that, at least for the
System.Windows.Forms.TreeView, the documentation is wrong: the hscrollbar does not go away with this style!! Doh! God knows how many times I had this working and thought I hadn’t because of the visual false positive :-(
</this should it what than longer me took>
Anyway, once I started testing properly again, not only it worked but I also realised that you don’t really need to send auto scroll info since it has some sensible defaults. So the bare minimum to get the TreeView to automatically scroll horizontally based on node selected and mouse position, is the following:
NativeMethods.SendMessage(treeView1.Handle, NativeMethods.TVM_SETEXTENDEDSTYLE, 0, NativeMethods.TVS_EX_AUTOHSCROLL);
If you actually want to change the speed of auto scrolling combined with a scroll timeout, then you must do this:
NativeMethods.SendMessage(treeView1.Handle, NativeMethods.TVM_SETAUTOSCROLLINFO, 30, 10);
And if you want to get rid of the hscrollbar to make it look like the windows explorer folder view, then you must do this:
int num2 = (int)NativeMethods.GetWindowLong(treeView1.Handle, NativeMethods.GWL_STYLE);
num2 = NativeMethods.TVS_NOHSCROLL;
NativeMethods.SetWindowLong(treeView1.Handle, NativeMethods.GWL_STYLE, num2);
The pinvoke declarations for this exercise are in this
NativeMethods file here.
For those of you that don’t want to repeat the above hacks for every single treeview in every single project, I’ve put all of the above in a TreeViewVista control. Just find a project that uses a TreeView already and change the ctor line to use
TreeViewVista instead :-)