|
-
May 14th, 2010, 01:35 PM
#1
Set ListBox item text without knowing what kind of object it is
Hi,
I'm creating an editable ListBox control, where the user can double-click an item to edit it. When double-clicked, I simply overlay a TextBox over the item, so the user can change the text and then commit it by pressing Enter or leaving the TextBox. The 'commit' is simply this:
Code:
Private Sub CommitText()
Me.Items(editingIndex) = textBox.Text
textBox.Visible = False
End Sub
where 'editingIndex' is the index of the item being edited, and 'textBox' is the TextBox object.
If the ListBox contains strings, this works just fine. The item being edited is replaced by the textbox Text string.
However, if the ListBox contains some other object (let's say a custom class), this is a problem! It still "works", in that it still sets the text of the item, but the item is no longer an instance of that custom class! It is now a String, and all other information about the item is lost.
So, I really want to let the user be able to change the text representation of ANY object, without replacing the object with a string. Obviously, I cannot know how the object displays its text (well, by the ToString function of course, but I cannot know what the ToString function returns).
As an example, consider this class:
vb.net Code:
Public Class Person Property Name As String Property Age As Integer Property Gender As String Public Overrides Function ToString() As String Return Me.Name End Function End Class
When an instance of this is added to the ListBox, it will display the Name property. So, when the user edits this instance, I want to change the Name property of the class, instead of replacing the class instance by a string...!
Now, I am having a few ideas how to approach this, but none really work the way I want.
I am pretty sure that I'm going to have to provide some kind of event that the user has to handle. I'm thinking something like this:
- When the item edit is committed, an event is raised
- This event contains the Item being edited (as an object, the user has to cast it himself), and the new text of the item.-
- The user handles this event, and assigns the new text to the correct property.
For the Person class, this could look something like this
vb.net Code:
Private Sub EditListBox1_ItemEdited(ByVal sender As Object, ByVal e As EditEventArgs) Handles EditListBox1.ItemEdited Dim p As Person = DirectCast(e.Item, Person) p.Name = e.NewText End Sub
My ListBox should raise this event, and assign the new item like this
vb.net Code:
Dim e As New EditEventArgs() e.Item = Me.Items(editingIndex) e.NewText = textBox.Text textBox.Visible = False RaiseEvent ItemEdited(Me, e) '<-- e.Item is edited here so it displays the correct new text Me.Items(editingIndex) = e.Item
I think this should work (although I haven't tested it), but there's one problem with this approach:
When the items are just strings, the user still needs to implement this event handler, while he shouldn't have to (I can simply assign the new text string to the item). So, if the user is simply using strings, he still needs to do this for every instance of my listbox:
vb.net Code:
Private Sub EditListBox1_ItemEdited(ByVal sender As Object, ByVal e As EditEventArgs) Handles EditListBox1.ItemEdited e.Item = e.NewText End Sub
(e might have to be passed ByRef for this to work..)
I don't want to force to user to do this if he is just using strings, my listbox should do that automatically...
So what I'm really looking for is a way so that I can implement the default behavior (for String items), and still allow the user to override this behavior if he is not using strings.
I may be overlooking the obvious solution here, but I can't figure it out... Overriding is done when you inherit a class, but the user isn't going to inherit my custom listbox (well he CAN, but he shouldn't have to). He is just going to handle the event. And if he doesn't handle the event, my listbox uses the default implementation...
Any tips?
Last edited by NickThissen; May 14th, 2010 at 01:41 PM.
-
May 14th, 2010, 01:55 PM
#2
Re: Set ListBox item text without knowing what kind of object it is
I think you have it about right from what I can tell.
Can't you just check the type of the object in the list and if it is a string, don't fire the event and just commit the change, otherwise if its any more complex type, raise the event to force the consumer to update the correct object's property with the new value?
-
May 14th, 2010, 02:12 PM
#3
Re: Set ListBox item text without knowing what kind of object it is
Thanks, that might be what I'm going to do after all.
I was thinking to also automatically handle numeric items (integer, double, etc), but perhaps it is better to force the user to handle them too (he can then check if the user input is numeric and don't commit if it isn't).
I was thinking about how you raise events in C# too... There, you have to check whether there are any listeners by checking if the event object isn't null. Then, if there aren't, I could use my own implementation:
csharp Code:
EditEventArgs e = new EditEventArgs(this.Items[editingIndex], textBox.Text); if (this.ItemEdited != null) { // user is handling event, let him deal with it this.ItemEdited(this, e); this.Items[editingIndex] = e.Item; } else { // nobody handling event, use default implementation this.Items[editingIndex] = textBox.Text; } textBox.Visible = false;
But there are a few problems:
1) How reliable is this?
2) What if the user handles the event, but simply doesn't do anything (empty method)? Then this doesn't work (but perhaps that is what the user should expect..?)
3) How do I do this in VB??
Anyway, I think I might go with your method after all, thanks!
-
May 14th, 2010, 02:53 PM
#4
Re: Set ListBox item text without knowing what kind of object it is
Well the thing is you can't predict exactly how someone will consume and use your class.
If they handle the event, but don't do anything in it, I would imagine the edit simply wouldn't commit. Just the same as if you set something to ownerdraw, but don't put any code in the paint event, you get a blank control. That is their problem to worry about, not yours. You provided them with the means to accomplish it, they need to do the rest.
Not sure what you mean by how would you do it in VB though??
-
May 14th, 2010, 02:56 PM
#5
Re: Set ListBox item text without knowing what kind of object it is
 Originally Posted by kleinma
Well the thing is you can't predict exactly how someone will consume and use your class.
If they handle the event, but don't do anything in it, I would imagine the edit simply wouldn't commit. Just the same as if you set something to ownerdraw, but don't put any code in the paint event, you get a blank control. That is their problem to worry about, not yours. You provided them with the means to accomplish it, they need to do the rest.
True.
 Originally Posted by kleinma
Not sure what you mean by how would you do it in VB though??
Well, in VB you just call RaiseEvent without checking for Nothing first. In C#, you check for null, and only raise the event if it isn't null.
Or can you simply check for Nothing in VB too? I can't try atm, but this?
Code:
If ItemEdited IsNot Nothing Then
RaiseEvent ItemEdited(Me, e)
Else
'...
End If
-
May 14th, 2010, 02:57 PM
#6
Re: Set ListBox item text without knowing what kind of object it is
in VB you just raise the event. If there is a listener wired up via AddHandler or a Handles clause on a subroutine, it will consume the event, otherwise it will not do anything.
-
May 14th, 2010, 03:00 PM
#7
Re: Set ListBox item text without knowing what kind of object it is
 Originally Posted by kleinma
in VB you just raise the event. If there is a listener wired up via AddHandler or a Handles clause on a subroutine, it will consume the event, otherwise it will not do anything.
Yes, but in C# you can check if there are any listeners. I know you don't have to do that in VB, but (with my previous code) I did need it, as I wanted to check if there were any listeners.
Anyway, checking if the type of the item is String is better, so I don't need it anymore, but I still want to know, kinda 
in other words: how do you check if there are any event handlers handling an event?
-
May 14th, 2010, 03:34 PM
#8
Re: Set ListBox item text without knowing what kind of object it is
To be honest, I don't know. Never had to travel down that road. I can see if I can find out, unless you find an answer first.
-
May 15th, 2010, 05:02 PM
#9
Re: Set ListBox item text without knowing what kind of object it is
Hmmm.... use a delegate instead? Events are just a wrapper to MultiCastDelegate.CombineImpl() and RemoveImpl(). You can use GetInvocationList() to get an array of registered event handlers to your delegate - just check the Length property.
-
May 15th, 2010, 06:26 PM
#10
Re: Set ListBox item text without knowing what kind of object it is
Nevermind, I figured it out. There appears to be a hidden "<Eventname>Event" propery or method or event or whatever it is, which you can check for nothing. So if my event is called "ItemEdited":
Code:
Public Event ItemEdited As EventHandler(Of EditEventArgs)
then I can use this to check if there are listeners:
Code:
If Me.ItemEditedEvent IsNot Nothing Then ...
It does not show up in the Intellisense but it works.
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|