dotnet listview look / feel like MultiListBox ?


#1

I’ve been playing around with the dotnet listview trying to make it look / feel like a MultiListBox control.
The style i’m using is System.Windows.Forms.View.List
The immediate differences are:
1. Even with ‘fullRowSelect’ on, it doesn’t really select a full row - only to the extent of the text.
2. I don’t need to be able to marquee select items yet still be able to click + drag select.
3. the MultiListBox has a black outLine around it which is not a big deal but would be nice to know
If you’re not sure about what I mean, check out the differences in this example code:

(
     	global lvTestRollout
     	try(destroyDialog lvTestRollout)catch()
     	rollout lvTestRollout "lvTestRollout"
     	(
     		local ListItems = #("These are some items", "for the example of", "the ListViews", "vs", "the MultiListBox")
     		
     		dotNetControl lv "System.Windows.Forms.ListView" height:150
     		multiListBox lb "MultiListBox" height:10
     		
     		fn initListView =
     		(
     			lv.backColor = (dotNetClass "System.Drawing.Color").FromArgb 225 225 225
     			--The following controls the display of details. We use defaults:
     			lv.gridLines = true
     			lv.View = lv.View.List
     			lv.fullRowSelect = true
     			lv.hideSelection = false -- show selected objects when listview is not in focus
     		)
     		
     		fn fillInListView =
     		(
     			theRange = for i in ListItems collect dotNetObject "System.Windows.Forms.ListViewItem" i
     			lv.Items.AddRange theRange
     		)
     		
     		on lvTestRollout open do
     		(
     			initListView()
     			fillInListView()
     			lb.items = listItems
     		)
     	)
     	createDialog lvTestRollout width:400 height:320
     )

EDIT: ok so i’ve answered the first 2 questions a few mins after posting…
It’s not 100% the same but close enough. It seems I need to use System.Windows.Forms.View.Details and add a column for fullRowSelect to work properly which also seemed to solve number 2. Even though you use a marquee selection, it behaves pretty much like the MulitListBox. I’d still prefer not to use the marquee if anyone knows of a way around it but it but as I said it’s close enough for now. Also I still havn’t figured out problem 3…


#2

Hello Joel,

you’ve answered most of your own question already. But this is what i came up with:

lv.View = lv.View.details
 lv.columns.add "" --add a column to be able to see the items
 lv.columns.item[0].width = lv.width
 lv.headerStyle = lv.headerStyle.none --hide the columnheader
 lv.borderStyle = lv.borderStyle.none --no border around the control
 --lv.borderStyle = lv.borderStyle.fixed3d --default border around the control
 --lv.borderStyle = lv.borderStyle.fixedSingle--a single black line around the control

In your example i don’t see a black outline around the multilistbox. The two example-controls look very much alike on my machine. I wouldn’t know how NOT to get the marquee.

Hope it helps,

Klaas


#3

thanks for the headerstyle tip, works great. I’ve made some headway with this since posting. I’ve now got a custom colored selection that remains visible when focus is lost as well as drag / ctrl+drag select / deselect that works like a MultiListBox. Still havn’t gotton rid of that marquee though…

Here’s the updated code if anyone’s interested:

(
	global lvTestRollout
	try(destroyDialog lvTestRollout)catch()
	rollout lvTestRollout "lvTestRollout"
	(
		local ListItems = #("These are some items", "for the example of", "the ListViews", "vs", "the MultiListBox")
		local hitNode
		local selMode
		local selModeActive = false
		
		local selColor = (dotNetClass "System.Drawing.Color").fromARGB 238 204 85 -- custom selection color (orangey-yellow)
		local lvBackColor = selColor.fromARGB 225 225 225
		
		dotNetControl lv "System.Windows.Forms.ListView" height:150
		multiListBox lb "MultiListBox" height:10
		
		fn initListView =
		(
			lv.backColor = lvBackColor
			lv.Columns.add "XRef Files:" (lv.width-4)
			lv.headerStyle = lv.headerStyle.none --hide the columnheader
			lv.Sorting = lv.Sorting.None
			lv.View = lv.View.Details
			lv.fullRowSelect = true
			lv.ownerdraw = true
		)
		
		fn fillInListView =
		(
			theRange = #()
			for i = 1 to 2 do join theRange ( for i in ListItems collect dotNetObject "System.Windows.Forms.ListViewItem" i )
			lv.Items.AddRange theRange
		)
		
		on lv MouseDown arg do if (hitNode = lv.GetItemAt arg.x arg.y) != undefined do
		(
			if keyBoard.controlPressed then selMode = NOT hitNode.selected
			else
			(
				for i = 1 to lv.SelectedItems.count do lv.SelectedItems.Item[0].selected = false -- clear the selection
				selMode = true
			)
			hitNode.selected = selMode
			selModeActive = true
		)
		
		on lv MouseMove arg do if selModeActive do
		(
			hitNode = lv.GetItemAt arg.x arg.y
			if hitNode != undefined do hitNode.selected = selMode
		)
		
		on lv MouseUp arg do
		(
			selModeActive = false
			if hitNode != undefined do hitNode.selected = selMode
		)
		
		on lv ItemSelectionChanged arg do
		(
			arg.Item.BackColor = if arg.isSelected then selColor else lvBackColor
		)
		
		on lv drawitem arg do
		(
			arg.DrawBackground()
			arg.DrawText()
		)
		
		on lvTestRollout open do
		(
			initListView()
			fillInListView()
			lb.items = listItems
		)
	)
	createDialog lvTestRollout width:400 height:320
)

#4

Gravey, this is good stuff, some bits I needed badly thanx!

-Johan


#5

hi joel,

the dotnet listbox control has a SelectionMode.MultiExtended or a SelectionMode.MultiSimple property that gives it a similar feel to a max multilistbox. I didn’t know if that was something you’d already looked at and dismissed in favour of the listview.

	try(destroyDialog lvTestRollout)catch()
 	rollout lvTestRollout "lvTestRollout"
 	(
 		local ListItems = #("These are some items", "for the example of", "the ListViews", "vs", "the MultiListBox")
 		local hitNode
 		local selMode
 		local selModeActive = false
 		
 		local selColor = (dotNetClass "System.Drawing.Color").fromARGB 238 204 85 -- custom selection color (orangey-yellow)
 		local lvBackColor = (dotNetClass "System.Drawing.Color").fromARGB 225 225 225
 		
 		dotNetControl lv "System.Windows.Forms.Listbox" height:150
 		multiListBox lb "MultiListBox" height:10
 			
 		on lvTestRollout open do
 		(
 			lv.backcolor = lvbackcolor
 			lv.SelectionMode =(dotnetclass "System.Windows.Forms.SelectionMode").MultiExtended
 			lv.items.addrange listitems
 			lb.items = listItems
 		)
 	)
 	createDialog lvTestRollout width:400 height:320
 )

#6

Hey Pete,

Thanks for the dotnet listbox info - I hadn’t considered it.
In this case I’d prefer a custom selection color as well. If you know a way of doing that with the listbox that’d be great, otherwise i’ll stick with the listview.

cheers


#7

With the listView control I have just changed the background colour of the selected object in the list. Not sure that you can directly set the colour of the selection.


#8

Hi Joel,

I think this would be possible, if not in max then with an inherited listbox control. I will have a ferret around and see if i can work it out.


#9

Hi Joel,

I think i’ve figured it out. I tried converting the VB code into something max could pallette, but it kept spitting it back at me. It was rejecting a method i was using in visual studio as being not relevant, but that’s probably because i was doing it wrong. In the end I wrote a small inherited control that does does the drawing of the selected node itself. It has a couple of extra properties in there too. Firstly, there is a selecteditemcolor property for the selected background, and also a selecteditemtextcolor property too, in case you need to invert the text or something. If you dont, just set it to the foreground color. here it is -

[left]click the image to download it. there is the MXscript file in the zip too. hope this is what you needed.
[/left]


#10

Paul: Thanks and check the last bit of code that I posted - I’ve already got it working.

Pete: Thanks heaps, your custom control works great. I wish I knew C# so I could do this kind of thing myself. 
I just read through my previous posts and it seems i forgot to mention something... I also needed individual control over the ForeColor of items, whether they are selected or not. Again, this is where I wish i knew C#... Can you suggest any good resources to get started in C# ? 
Either way I wont trouble you for the ForeColor part, I'm not sure if it'd be so 'easy' with the ListBox since its Items are just strings and not 'ListItem' objects with their own properties. The ListView will be fine - and we've now got a great custom ListBox control too! Thanks again for that.

#11

Hi Joel,

You’re welcome!

So you actually wanted to be able to color any item a different foreground color? I’ll look into that but Im not sure if it’s straightforward from the small amount i found on custom listboxes on the web. There might be a control on one of the code sites that does what you ask.

As for resources, I dont actually use C#, all my controls are written in VB. the great thing about dotnet is that you ca reference C# classes in Visual studio and use them in another language, as the method/function/property calls are identical. So for example the trackbar I posted earlier in the week uses a C# component referenced in the VB class library. For me, VB seemed much easier to grasp for my feeble brain. I have just spent the last year hitting the books and the web hard over the subject!

glad the control worked for you! cheers, Pete


#12

Here’s a thought - you could imlpement individual item color control with a set of private color properties. These would be hidden and accesible via a public method something like itemforecolor <itemindex> <color>
Then, when the control draws itself it looks for a color property for that item index. if not, it defaults to the forecolor. This is only useful if you want absolute control over the item color. Since you can call it anytime, you could filter the colors per item when you populate the listbox. This would mean a color per item, and without iterating through something that you dont know how many, you could set up color properties for, say the first 30 items? or more but it depends how you think the control will be used. Its a nasty solution true, but just my first thoughts. :shrug: im happy to implement this solution into the control if you thought it would be useful.


#13

Interesting that you use VB. Either way I dont have much experience with compiled languages, lots of maxscript and a small amount of python are all I have time for at the moment. I bought a C++ some time ago but I haven’t gotton around to starting it yet…

I’m not quite sure I understand exactly what you mean by this. I get the first part about setting custom colors via a public method but you lost me when you started talking about the first 30 items. 30 may be enough but I would prefer not to limit it to just 30. Check out the Xref Scene Dialog’s ListBox to see what I’m going for. When you disable an xref and it’s not selected, the item’s forecolor becomes a light red color. I’d prefer the ‘disabled color’ to remain whether it is selected or not. Either way I’m guessing that the ‘on checked’ event is set to trigger the color change in the selected items. If your solution works something like this and you’re still happy to implement it then I’m happy to let you :slight_smile:
Thanks again!


#14

Hi joel,

30 was a number i just plucked out of my head, you could have more but it would have to ‘hardcoded’. Having properties in the control is the same as storing parameters in a maxplugin. It’s only different in that i would disable them from editing directly by making them private. that way, a single method can set them from inside the class.

This is why my idea is not terribly scalable. however, for what you want maybe a listview would give you that control. However, you could trigger the change in color if you have a callback method that notifies when you’ve disabled an xref. I guess you would have to keep repopulating the control according to the object’s state that you are using. As it is drawing the listbox items manually, it would reflect this change almost immediately. I might not be grasping fully the kind of thing you’re doing here though so I might be way off. cheers!


#15

Pete thanks again for your help. I’ve got a ListView solution working for now. I guess it’s just a nit-picky thing because I don’t need / want the marquee selection in there. Besides that it seems to work fine.

Maybe creating a solution for the ListBox that is more dynamic than hardcoding, can be my motivation for learning a compiled language.

Cheers Pete. This one’s on me: :beer:


#16

IMHO:
Unless you know you want to invest the time in some serious theory from the outset, or have to write to existing code, I wouldn’t start with C++, these days, when there are other languages like C# around. C++'s advantages lie at a lower programming level than you probably need to go, and its disadvantages lie in having to do your own memory management, and numerous subtle gotchas that are a natural consequence of its power at that lower level.


#17

not to mention it makes b*gger all sense! :slight_smile:


#18

I thought it might be useful to know C++ for writing compiled max plugins some day, however I have no immediate need to do so, so thanks for the tip. I have heard good things about C# so I’ll most likely start on that when I get a chance. Perhaps you know of some good resources for getting started?


#19

hi joel, i obviously look for more vb orientated sites, but i have used http://www.csharpcorner.com/ and www.codeproject.com is still a place i visit a lot. The web is literally teeming with info but i like to hit the books first to get a grasp! i just searched amazon and read the reviews!


#20

Oops!:slight_smile: I thought you might ask that, and since I came across from C++ ( which is very like C#), I went straight to the Visual Studio help, MSDN articles and reference, and the internet sources. That might not be very helpful, but if you’ve picked up enough OOP from Python, that might be OK. You can almost always rely on O’Reilly books to be concise and not waste your time.

There are 3 bits to learn really, not necessarily in this order: 1.General OOP, 2.the language’s syntax and good style, and 3. whichever library or framework you’re calling from the language, to build your projects. 1 can help speed up searching and making sense of the references in 3.

C# might be to too closely associated with MS and .net, if plugins are your priority. I have to admit the struggle for me is 3, (the Max SDK) at the moment, so you might find, if you learn C++ for it, the job is only half done!