|
|
Comments and Discussions
|
|
 |

|
I have used this library on a project, and it works beautifully on multiple machines. Great work!
|
|
|
|

|
OOps. Sorry about the mailbox. I emptied it...
This worked for me, but the Jumbo version fails:
If m_xlgImgList <> IntPtr.Zero Then Dim flags As ShellAPI.ILD = ILD.NORMAL = 0
If item.IsLink Then flags = flags Or INDEXTOOVERLAYMASK(ovlLink)
If item.IsShared Then flags = flags Or INDEXTOOVERLAYMASK(ovlShare)
Dim hIcon As IntPtr = IntPtr.Zero
rVal = GetNonOverlayIndex(item, GetOpenIcon)
hIcon = ImageList_GetIcon(m_xlgImgList, rVal, flags)
rVal = ImageList_ReplaceIcon(m_xlgImgList, -1, hIcon)
Debug.Assert(rVal > -1, "Failed to add overlaid xl icon")
DestroyIcon(hIcon)
Debug.Assert(rVal = rVal2, "XL & Large Icon Indices are Different")
End If
End SyncLock
(The 'ovlLink' and 'ovlShare' are offsets of the Shell ImageList's own overlay icon; they are retrieved using 'SHGetIconOverlayIndex' (shell32.dll))
|
|
|
|

|
1st - great work, J.P. - 5x*
I succeeded in adding overlays to 'm_xlgImgList' using the 'ImageList_GetIcon(m_xlgImgList, rVal, flags Or INDEXTOOVERLAYMASK(2))' method
('2' being the HImageList internal 'link' icon), producing nice XL icons, properly overlaid, where applicable.
But I cannot make it work on the Jumbo (256x256) -- m_jumboImgList; I've tried ImageList_Add(himl,bm,mask), ImageList_Replace etc. etc., but to no
avail...
Any suggestions?
Sincerely,
Jens, Denmark.
|
|
|
|

|
At this point, I have no idea how to do what you want to do.
I have replied via private email with a bit more of an elaboration of my initial response.
Jim Parsells
|
|
|
|

|
My private mail to you was bounced - your mailbox is full.
I was giving you my email address and asking you to send me the changes that you made to get overlaid XL icons.
Jim
|
|
|
|

|
Hi
I have an app with 2 exptree controls and 2 listview .
What I need is a way of control when a folder is created and only update the listview that I want.
I just can't figure out how to do this.
Can you help me ?
Thanks
Fernando
|
|
|
|

|
I'm not completely sure what you are asking
It is certainly possible to have two ExpTree controls each associated with a different ListView.
Of course it is up to your code to keep track of what each ListView is displaying.
One way of doing that is to have an EventHandler for each ExpTree and appropriate EventHandlers for each of the ListViews.
Because of a design flaw in ExpTree, its ExpTreeNodeSelected Event does not include the normal "sender" parameter, so, you really do need to have a separate Handler for each ExpTree Control's ExpTreeNodeSelected Event. Obviously, those Handlers could be separate little routines which call another routine which does the common processing. For example... the following code has not been tested in any way, including the fact that it was created in a text editor rather than Visual Studio so it may well contain typos and other errors!!!
Private LastSelectedCSI1 As CShItem
Private LastSelectedCSI2 As CShItem
Private Sub AfterNodeSelect1(ByVal pathName As String, ByVal CSI As CShItem) _
Handles ExpTree1.ExpTreeNodeSelected
NodeSelected(CSI, ListView1, LastSelectedCSI1)
End Sub
Private Sub AfterNodeSelect2(ByVal pathName As String, ByVal CSI As CShItem) _
Handles ExpTree2.ExpTreeNodeSelected
NodeSelected(CSI, ListView2, LastSelectedCSI2)
End Sub
Private Sub NodeSelected(ByVal CSI as CShItem, ByVal lv1 as ListView, ByRef LastSelectedCSI as CShItem)
LastSelectedCSI = CSI
End Sub
Private Sub DoItemUpdate(ByVal sender As Object, ByVal e As ShellItemUpdateEventArgs)
Dim LastSelectedCSI as CShItem
Dim lv1 as ListView
Dim Parent As CShItem = DirectCast(sender, CShItem)
If Parent Is LastSelectedCSI1 Then
LastSelectedCSI = LastSelectedCSI1
lv1 = ListView1
ElseIf Parent Is LastSelectedCSI2 Then
LastSelectedCSI = LastSelectedCSI2
lv1 = ListView2
End If
If LastSelectedCSI IsNot Nothing then
Try
End Try
End If
End Sub
There a other Event Handlers that you will need to fix up to handle to two ExpTree/ListView combinations. Do not forget those found in the Region...
#Region " Form Load/VisibleChanged lv1 HandleCreated"
Otherwise lots of things won't work!!!
|
|
|
|

|
Thank you for answer I will try your code to see if solves my problem.
I'l try to explain what my problem is . Is it possible to add a picture to this msg ? That would help you understand my problem.
I have two Exptree and two listview ( side by side ). I select different folders on each exptree control.
The problem I have is when I create a folder.
For instance , if I create a folder under the select folder on right exptree control, the new folder appears on right listview but also on left listview.
I don't understand why.
Or if you don't could you send me an email and I would send an image with the error.
Thank you
|
|
|
|

|
I suggest you look very closely at my last reply, especially the part about changing DoItemUpdate to correctly process change messages. The exact code may or may not work, but the implications need to be understood and dealt with.
The symptom you describe corresponds exactly to what will happen if you do not maintain a "LastSelectedCSI" type of variable for each ListView. CShItem's change notification does not know what you are doing with the notification and definitely does not know what ListView you are displaying the Folder content in. All the notification process knows is which Folder was changed. It is up to your code to decide where (or if) to show the change.
This requires that your code knows which ListView is currently showing which Folder. Given that, your code can determine, using the "Is" operator, which ListView needs to be updated.
Here is the relevant code. It is the same as I sent before, but with the indentation fixed to properly show the real heirarchy.
Private Sub DoItemUpdate(ByVal sender As Object, ByVal e As ShellItemUpdateEventArgs)
Dim LastSelectedCSI as CShItem
Dim lv1 as ListView
Dim Parent As CShItem = DirectCast(sender, CShItem)
If Parent Is LastSelectedCSI1 Then
LastSelectedCSI = LastSelectedCSI1
lv1 = ListView1
ElseIf Parent Is LastSelectedCSI2 Then
LastSelectedCSI = LastSelectedCSI2
lv1 = ListView2
End If
If LastSelectedCSI IsNot Nothing then
Try
End Try
End If
End Sub
The key parts are the If .... ElseIf .... EndIf clause which determines which (if any) of the ListViews should display the change ... followed by the If ... IsNot Nothing statement which deals with the case that the change is not of interest to either ListView.
Jim Parsells
|
|
|
|

|
Hi
Your code did help to solve the problem .
I also changed the code to deal with folders that are deleted.
I changed function FindLVItem . I added a parameter called lista to pass the listview I want to reflect the changes . Now it looks like this
Private Function FindLVItem(ByRef lista As ListView, ByVal item As CShItem) As ListViewItem
For Each lvi As ListViewItem In lista.Items
If lvi.Tag Is item Then
Return lvi
End If
Next
Return Nothing
End Function
Thank you very much for your help.
Fernando
|
|
|
|

|
Glad to be of help
Since the Demo forms use one TreeView/ListView pair, their code makes assumptions about only having the one TreeView/ListView pair. Review and test the code very carefully to ensure that you have covered all cases where having two pairs might cause subtle errors.
I suspect that having a Class which handles the bookkeeping, 1 Class Instance for each pair, would be a bit more robust. It depends on how much time and effort you want to put into it.
|
|
|
|

|
Thanks again.
I'l try your sugestion.
Fernando
|
|
|
|

|
How to return the selected folder full real? No system name.
Example 1: If you select Documents, returning c: \ users \ xxx \ documents and not Documents.
Example 2: If you select Pictures, returning c: \ users \ xxx \ pictures and not "Pictures".
from Brazil
|
|
|
|

|
It is working as intended. If you wish to translate back to "Documents", etc. you have to do it in your application.
Jim Parsells
|
|
|
|

|
Hi i found your project very good. I have a question how to handle button click to specify list the contents of a directory to lv1?
Instead of the treeview, a button would be used
|
|
|
|

|
See the code in frmTemplate or frmThread in the lv1_DoubleClick Region. In essence, you call ExpandANode giving it the CShItem of a Folder.
Private Sub lv1_DoubleClick(ByVal sender As Object, ByVal e As System.EventArgs) Handles lv1.DoubleClick
Dim csi As CShItem = lv1.SelectedItems(0).Tag
If csi.IsFolder Then
ExpTree1.ExpandANode(csi)
Else
.
.
The problem comes from the question of where do you get the needed CShItem! Each ListViewItem and TreeNode has the proper CShItem in its' .Tag. Your Button Click Handler needs to know which Directory it is supposed to list the contents of. How is the association between your Button and the Folder to display being made?
Jim Parsells
|
|
|
|

|
Thanx again for your work!
A problem I stumbled upon: In Win7 (32 and 64) I only get updates f�r inserting and deleting files, but not for renaming. Tried it with V3.0 and had the same effect. It seems that there are no notifications coming from the system f�r renames/updates, in debugging mode nothing is shown from EventDump. Do you have any idea ?
|
|
|
|

|
Thanks for your vote!
Hmmm...It is quite true that if Windows does not provide appropriate message(s), then ExpTreeLib will not recognize a change. However, I am unable to reproduce this failure. Is there anything special about the file(s) whose renaming is not reported? In particular, the quick tests that I just ran were for renaming files on the local machine in a directory that I have full Control permission.
My tests were done with both the download Demo zip and with a more instrumented version in Debug mode. I renamed the file both via the app and via Windows Explorer. In all cases the rename was reflected in both the app and in Windows Explorer. All tests were run on Win7 - 64 bit.
Another possibility...How were you doing the Rename? In some earlier versions of Windows the raising of update messages was more the resposibility of the app that makes the change. I have not seen this in Vista or later versions, but ....
Of course all of this was tested much more completely before I published Version 3.0 and 3.1.
Jim
|
|
|
|

|
OhOhOh, I did the renames with an Exlorer-like tool, which in fact is rather old, but seemed to work still .... with Windows Explorer everything is ok. Sorry to bother you, I think I have to use a new tool!
Thanx again for your outstanding work - Klaus
|
|
|
|

|
Hi ,
First things first : Good job
However , there was a request that I wanted to put forth. Could you also implement overlay icons support ( for example - tsvn )?
Thanks and Regards
Gagan Janjua
|
|
|
|

|
Thanks for the vote!
Overlay support in what sense? As you can see from the screenshot in the article, the "Shortcut" overlay is, in fact, displayed.
Actually, overlay support is somewhat primitive, but is adequate for my (and most other)purposes, I hope. I basically let Windows do the work.
Jim
|
|
|
|
|

|
ExpTreeLib's Icon handler is SystemImageListManager. At its' heart, it uses an API call like:
SHGetFileInfo(.PIDL, dwAttr, shfi, cbFileInfo, dwflag)
with the appropriate flags to obtain the Icon with or without Overlays from the Shell. The key question is what dwflag settings are appropriate? SystemImageListManager only asks for Overlays for Link and Shared files. Setting SHGFI.ADDOVERLAYS for all files might well give unexpected results, mess up the logic, and add to the CPU and/or Memory burden of obtaining and using Icons.
If you want to play around with SystemImageListManager, feel free and also let me know what you did and how it turned out. I might be tempted to try it myself if I had TortoiseSVN installed anywhere.
Jim
|
|
|
|

|
Your application seems to be an excellent source of teaching, at least for me.
I tryed to Add new Form in your Demo application with only a Button and in its Click event:
Dim Frm1 As New frmThread
Frm1.Show()
and in main sub:
Application.Run(New Form1)
now, run application, click and open just one instance of FrmThread(I assume StartUpDirectory=Desktop, but this isn't the problem).
Create a new folder and open it. Now create a new file\folder in the folder just created.
Now you have to open a new instance of FrmThread by clicking on Button in Frm1.
The exception raised is "ArgumentOutOfTheRangeException: Specified argument was out of range"
Note that if no file\folder is created you can open more FrmThread without any error!
Anyone have any suggestions on how can I fix this?
Ps. Sorry for my English.
Thaks in advance.
|
|
|
|

|
I probably know how to fix this I say "probably" because I was unable to reproduce an "ArgumentOutOfRange" exception. However, with some extra manipulation of one of the two frmThread instances I was able to cause a Null argument exception. This occurs in the same area of code that I suspect you are getting your observed problem, and the fix is probably going to clear up your problem.
If it does not fix your problem or if you encounter other problems, it would be most helpful if you included a Stack Trace in your message. A bit more detail of what you did to produce the error would also be helpful.
The fix is in the ExpTree.BeforeExpand Event Handler at approximately line 558 in ExpTree.vb.
Remove the line that says:
e.Node.Nodes.Clear()
Add the following in the same routine:
If D.Count > 0 Then
D.Sort() e.Node.Nodes.Clear()
The inserted line is the one with the '11/03/2012 Comment.
This change leaves the "Dummy" node in the TreeView while CShItem.UpdateRefresh (which is called by the CSI.Directories call in the line prior to the Sort). In cases such as the one you describe, UpdateRefresh will Raise Events whose Handler assumes that an empty .Nodes in the TreeNode means that a "Dummy" node needs to added. If the Handler sees a "Dummy" node, it understands what the proper handling of the .Node should be.
Jim
|
|
|
|

|
Thanks for reply but your fix dosen't resolve the problem. To reproduce the exception I advice you to follow my example in first post. I repeat, if no changes made you can open also 100 FrmThread, but if you add a file\folder in one instance of it and open a new instance was raised the exception ArgumentOutOfRange.
Using Intellitrace I found that the exception was raised in GetTreeNode on
TreeNode= tv1.Nodes(0)
So I inserted before this
If tv1.Nodes.Count = 0 Then Exit Function
Seems to be no problem. Let me know if it works and There's no problem.
|
|
|
|

|
OK, this occurs somewhere in the same chain of events as the fix that I sent you. Differences in the environment (machine, number of files, etc.) may change the timing a little bit. Retain the fix that I originally posted and keep the change that you suggested. Both of these will be in my next update. For clarity's sake, I would change your fix to:
If tv1.Nodes.Count = 0 Then Return False
Jim
|
|
|
|

|
Jim,
Well Done! I have been using my own (less sophisticated, but worked great for my needs) Directory and File control for years. I just upgraded to Windows 8, Visual Studio 2012... and found it lacking. As much as I love creating my own controls I don't see any need to spend my time, other than the learning experience and self gratification, in trying to reinvent the wheel when yours already has chrome rims and spinners.
Thanks,
SSDiver2112
|
|
|
|

|
Thanks for the Vote and comment.
Let me know if you encounter any problems using the control with Win8. I have only lightly tested it in that environment. There shouldn't be any problems, but ...
You may be interested in the fix discussed below in this Forum. It is a minor fix, but easy to make and removes an annoyance.
I do have one unpublished bug fix. Again, it is not a big deal, but it is really a bug. I did some refactoring while making the fix so it does not lend itself to a Forum post. Send me an email address via email reply and I will send you the fix.
Jim
|
|
|
|

|
First I want to say, great code. works great in my project, thank you for this.
when I use the listview and I select the "tile" view, the icons are just 32 by 32 pixels. is there a way to make icons bigger? such as 48x48.
Anton
|
|
|
|

|
Since it all is just code, then the literal answer is, of course, Yes. However, it is not too easy. Most people solve this by making the ListView an OwnerDraw control. This is not necessarily the only way to approach the problem given ExpTreeLib.
On XP or later systems, SystemImageListManager does maintain an Imagelist for eXtralarge Icons (48x48). It has a method (GetXLIcon that will retrieve a 48x48 Icon given its' IconIndex. It also maintains a Handle for the eXtraLarge Icon list (m_xlgImgList).
However, the ListView control only supports 2 ImageLists (small and large). The LargeImagelist of the ListView is where it retrieves the Icons for the Large Icon View and the Tile View. With a little bit of change to SystemImageListManager and to the routines mnuViewTile_Click and mnuViewLargeIcons_Click in your Form, it is possible to dynamically change which ImageList is used for the ListView's LargeImageList.
Check out SystemImageListManager's routine "SetListViewImageList" for clues as to what is required there. Do not forget the bookeeping required in your Form, especially in the VisibleChanged Event Handlers.
Jim
|
|
|
|

|
Outstanding work!
Demo works perfectly with VStudio Express 2012. When using an own form, I had to set the ExpTreeLib.StartUpDirectory in the Load-Procedure of my form (when I wanted Desktop as StartUpDirectory), but then everything was ok.
Thanks for this really, really helpful library.
Best regards - StyrianOak
|
|
|
|

|
Thanks for the vote
When initially placing ExpTree on a Form, it is often (always?) required to change the StartupDirectory one time before it will fill correctly in the IDE. If you want the Desktop to be the StartUpDirectory, then change it in the IDE to something else and then change it back to the Desktop. Once that has been done - one time only - you should never have to set it in the Load EventHandler unless you want to set it to something else (eg C:\Test).
The steps then are:
1. Place ExpTree on Form
2. In IDE, Change StartUpDirectory to "MyComputer" or anything else from the list. ExpTree is populated.
3. In IDE, Change StartUpDirectory back to Desktop. ExpTree is re-populated.
4. Done - never have to do this again.
You should not have to reset to Desktop in the Load Handler unless you want the StartUpDirectory to be something other than a SpecialFolder.
This has been a feature? pretty much in all versions.
Jim
|
|
|
|

|
Weird - When I use your Demo-App, everything is like you wrote. When I use my own form with SplitContainer, ExpTree and ListView, I have to change and reset the StartUpDirectory every time I start the IDE, also I have to reset it in the Load Handler. This happens only with the Desktop as StartUpDirectory, not with other settings. I tried in VStudio Express 2010 and 2012, German, on a Win7 64 Bit german system.
It's not a big deal for me, just wanted to tell you the story. I like ExpTree anyway!
Regards - Klaus aka StyrianOak
|
|
|
|

|
That is strange!
Take a look at your Form's Designer code and compare it to the Designer code of any of the demo Forms.
The basic flow is that your Form's Designer will create a New instance of ExpTree.
The New routine in ExpTree will, at that point, wire the Handler for the StartupDirectoryChanged Event. The EventHandler is the routine "OnStartUpDirectoryChanged".
Later in your Form's Designer, the StartUpDirectory Property of ExpTree will be set to whatever you set in the IDE.
Setting the Property will Raise the StartupDirectoryChanged Event. The Event Handler in ExpTree will then create and display the contents of the Tree.
I have not looked at this for a very long time, but, if memory serves, under some circumstances, the Form's Designer code will not include the Property setting statement. That statement should look something like:
Me.ExpTree1.StartUpDirectory = ExpTreeLib.ExpTree.StartDir.Desktop
That statement is generated by the visual designer code of the IDE, and sometimes it is not generated!
Now that I think about it, I suspect that the problem lies in the Property declaration in ExpTree. That now reads:
<Category("Options"), _
Description("Sets the Initial Directory of the Tree"), _
DefaultValue(StartDir.Desktop), Browsable(True)> _
Public Property StartUpDirectory() As StartDir
If I am correct, then the problem may be cured by changing that declaration to:
<Category("Options"), _
Description("Sets the Initial Directory of the Tree"), _
Browsable(True)> _
Public Property StartUpDirectory() As StartDir
Try that out and let me know if it makes a difference.
Jim
|
|
|
|

|
Hi!
Your changed Property-Definition is working now, the correct setting of the property is generated in myform.designer.vb and everything is working fine.
Thanx for your help - Klaus
|
|
|
|

|
Thanks. I did not think this speed could be achieved with VB
Bertram
|
|
|
|

|
Thanks
Actually, VB.Net and C# are basically the same language with different syntactic sugar. To get real speed you must use unmanaged C/C++, but it is very rare that that is required.
In this case, the key is knowing how the .Net Classes and the Windows API work on different OSes.
Jim
|
|
|
|

|
My next effort was to do a minimum check to see how ExpTreeLib worked on Win8. Of course this involved:
1. Setting up a new VMWare Virtual Machine
2. Installing Windows 8 Release Preview
3. Learning how to navigate around in Win 8 (this is a work in progress)
4. Running the Demo download.
I managed to do all this - not without a few bumps in steps 2 and 3.
The Demo as published here works - limited testing, but so far so good. Of course it only works on the Desktop. The visual portions of the Library are not, and never will be, suitable for Metro. The non-visual portions (CShItem and all its' many friends) may well have some use running behind a Metro app. This is TBD.
Jim Parsells
|
|
|
|

|
Your tenacity in keeping this evolving is exemplary.
best, Bill
It keeps me humble to think there's more bacteria in my gut than neurons in my brain, and that twenty trillion neutrinos pass through one hand a second, and that the average mattress contains 20 million bedbugs each of whom sh*ts once per hour.
|
|
|
|

|
As someone who has followed this project for years and had the pleasure to use it in a few of my own little projects. This update is great. Thank you!
|
|
|
|
|
|
|
|
|

|
Jim Parsells wrote: See the demo forms, the Help file, and the other included documentation for additional code elements needed to support your application's use of CShItems.e of CShItems.
Is the bolded part the result of an editing mishap? I think it should be removed.
Anyways, nice article!
Bill Gates is a very rich man today... and do you want to know why? The answer is one word: versions.
Dave Barry
Read more at BrainyQuote[ ^]
|
|
|
|

|
It is a CodeProject queue to be fixed.
Thanks for pointing it out.
Jim
|
|
|
|

|
Thank-you for sharing this, Jim. Your ExpTree component is an absolute must for adding Windows Explorer style functionality to a .Net project.
|
|
|
|
|
 |
|
|
General News Suggestion Question Bug Answer Joke Rant Admin
|
A Class Library for building Forms with a folder navigation TreeView and form specific ListViews that can be tailored for your application and behave like Windows Explorer. Full documentation.
| Type | Article |
| Licence | CPOL |
| First Posted | 16 Jul 2012 |
| Views | 16,046 |
| Downloads | 3,420 |
| Bookmarked | 40 times |
|
|