|
-
May 27th, 2004, 06:12 PM
#1
Thread Starter
Frenzied Member
Identify a control from parameters passed to event handler?
Esteemed Forum Participants and Lurkers:
I'm still playing with arrays of buttons, and the more I get into it the more I realize why VB.Net is so cheap. It certainly lacks a lot of features I have experienced in the past.
It is nice that button click calls can field more than 1 button, but what use is it? I can field as many buttons as desired in a single call, but as far as I can tell, there is no intrinsic way of telling which button activated the call!
Playing around with an array of 10 Radio Buttons I discovered (NEWBIE ALERT!) that "sender" merely indicates what kind of control initiated the event, and "e" merely states that this handler has gotten a system event! Whoopie doo! I want to know WHO initiated the event! Which of my 10 Radio Buttons am I dealing with? I would like to CASE the buttons, but I sure don't know how without a "who" parameter. LabWindows CVI very nicely passed the ID of the control to the event handler. VB.Net leaves me out on a limb looking for kludges. Is there some high-class function that returns all "checked" buttons from a collection? That would be neat (since there is only 1)!
Code:
Private Sub RadioButton1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles RadioButton1.Click
' Which control is checked?
MsgBox(sender.ToString) ' Whoopie doo! a Radio Button
MsgBox(e.ToString) ' Whoopie doo! a System Event
End Sub
Am I missing something?
I still need a GOOD book! Any recommendations?
Blessings in abundance,
All the Best,
& ENJOY!
Art . . . . Carlisle, PA . . USA
-
May 27th, 2004, 08:55 PM
#2
Lively Member
like this?
VB Code:
Public Sub radiobuttons_click(ByVal sender As Object, ByVal e As EventArgs) Handles RadioButton1.Click, _
RadioButton2.Click, RadioButton3.Click, RadioButton4.Click, RadioButton5.Click, RadioButton6.Click, _
RadioButton7.Click, RadioButton8.Click, RadioButton9.Click, RadioButton10.Click
MessageBox.Show("who am i? " & sender.name)
End Sub
if not, sorry...
-
May 27th, 2004, 09:33 PM
#3
Lively Member
or this? i don't know. hope this helps...
VB Code:
Dim r(9) As RadioButton
Function idontknow()
Dim i As Integer
Dim y As Integer = 22
For i = 0 To r.Length - 1
r(i) = New RadioButton()
r(i).Name = "radio button " & i
r(i).Text = r(i).Name
r(i).Location = New Point(20, y)
y += 22
Me.Controls.Add(r(i))
AddHandler r(i).Click, AddressOf xidontknow
Next
End Function
Public Sub xidontknow(ByVal sender As Object, ByVal e As EventArgs)
MessageBox.Show(sender.name)
End Sub
and oh, please don't say VB.Net is so cheap...
Last edited by ayan; May 27th, 2004 at 09:36 PM.
-
May 27th, 2004, 11:23 PM
#4
As ayan points out its not that '"sender" merely indicates what kind of control initiated the event' sender IS the control that raised the event.
It is wise to cast the sender to its proper type if you know what it is. Then you can access its members correctly.
VB Code:
Private Sub RadioButton1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles RadioButton1.Click
'cast it
Dim rb As RadioButton=Ctype(sender,RadioButton)
'use it
Msgbox(rb.Text)
End Sub
-
May 28th, 2004, 08:43 AM
#5
Thread Starter
Frenzied Member
Thanks to you all for your gracious help ... I still need a recommendation for a GOOD book!
Your comments were ALL excellent and I'm starting to pick up speed in this stuff now.
I just didn't intuitively make the connection that "sender" was a handle to the actual radio button! All I could find in the Help pages under System.Object was "ToString" which I thought would give me useful info about the identity of "sender".
Thanks to Edneeis for REALLY clarifying the point ... now I just need to dig deeper into the casting concepts. I was surprised that "sender.checked" gets through the editor unscathed and operable (returns "True"), even though the "checked" is not recognized as a property of sender by the editor (it stays "checked" instead of getting corrected to the proper "Checked"). I'm presuming if I cast "sender" to RadioButton as Edneeis recommends that the editor will miraculously recognize all of the RadioButton properties of sender. I previously had problems getting "Checked" recognized at all when I indirectly referenced a RadioButton as "Control", but it worked (of course) when I referenced it as a RadioButton.
My apologies for letting my frustration show through in my posting, and thank you all for your gracious assistance.
I still need a recommendation for a GOOD book!
Blessings in abundance,
All the Best,
& ENJOY!
Art . . . . Carlisle, PA . . USA
-
May 28th, 2004, 08:50 AM
#6
Frenzied Member
Why would you need to cast sender to a radiobutton in a radiobutton click event? Wouldn't sender always be a radiobutton? Or does it come across as a generic object? Just curious.
-
May 28th, 2004, 10:14 AM
#7
Thread Starter
Frenzied Member
Savelinus ...
The system knows that sender is a RadioButton AT RUN TIME! If you cast sender to RadioButton while building the code, I think that all of the RadioButton properties for sender will be recognized.
While you are editing, without the cast, the ONLY 'automatic' property that you have for sender in the popup menu is "sender.GetType()". My guess is that after you cast sender to RadioButton, when you type "sender." the entire resources for RadioButton will appear in the popup, including "Name", "Checked", and "TabIndex".
My handler now fields all 10 buttons! The Button function names (departments) are loaded in a Global array by TabIndex, and I can now process everything just by reading the TabIndex for sender!
Set the TabIndex of each button as 0 through N
In a module ...
Code:
Public g_Name as String = _
{"Dept1","Dept2", ... ,"DeptN"}
'The Handler:
If sender.Checked Then
'TEST TEST TEST TEST
MsgBox("This is the " + g_Name(sender.TabIndex) + " Department")
'END TEST
End If
It really works GREAT!
Blessings in abundance,
All the Best,
& ENJOY!
Art . . . . Carlisle, PA . . USA
-
May 28th, 2004, 10:47 AM
#8
Frenzied Member
Hmm, so the cast is for intellisense when coding, then?
Anyway, if you're going to use tabindex, you might want to look at the tag property instead. If you use tabindex, you'll have to be sure it never changes.
-
May 28th, 2004, 11:11 AM
#9
yay gay
Originally posted by salvelinus
Hmm, so the cast is for intellisense when coding, then?
Anyway, if you're going to use tabindex, you might want to look at the tag property instead. If you use tabindex, you'll have to be sure it never changes.
Hmm, actually the casting is to make sure you are working with the correct data type and can access its properties/data members, and a consequence of that is having the IDE showing you the class' things
\m/  \m/
-
May 28th, 2004, 11:14 AM
#10
salvelinus - I've been having success reading the book Mastering Visual Basic .NET by Evangelos Petroutsos (Sybex Publishing).
It's a very thick book, and taks some getting used to, but so far it's been very helpful to me.
TG
-
May 28th, 2004, 02:35 PM
#11
Thread Starter
Frenzied Member
Salvelinus ...
I don't think VB mungs with the TabIndex property of a control after you assign it ... if you set them on the Form as you design it I think they are safe. It IS possible to set more than 1 control with the same index though! I just created my panel and then did a "View > Tab Order" and made sure everything was in order.
PT Exorcist ...
So far I haven't found any properties of the RadioButton that weren't recognized at run time without casting "sender". So at run time, "sender" seems to have all the properties (of the RadioButton that generated the event) by default, so casting doesn't seem to be absolutely necessary. It would be hard to cast "sender" if you were processing more than 1 type of control, but I can't imagine wanting to handle different types of controls through a common handler. Casting does make the code absolutely clear, and it is easier to write the code!
Techgnome ...
Thanks for the book comments.
Blessings in abundance,
All the Best,
& ENJOY!
Art . . . . Carlisle, PA . . USA
-
May 28th, 2004, 03:06 PM
#12
Frenzied Member
Originally posted by PT Exorcist
Hmm, actually the casting is to make sure you are working with the correct data type and can access its properties/data members, and a consequence of that is having the IDE showing you the class' things
Well, either a radio button is being passed in as sender, and wouldn't need a cast, or is passed in as an object, so needs a cast to access its members and properties. In a click event I don't see why you'd need to check for the correct data type in the first case, unless some other sender is handling the click event. The second case, sure.
Originally posted by Webtest
I don't think VB mungs with the TabIndex property of a control after you assign it ... if you set them on the Form as you design it I think they are safe.
It won't change them if you delete something? Didn't know that.
Originally posted by techgnome
I've been having success reading the book Mastering Visual Basic .NET by Evangelos Petroutsos (Sybex Publishing).
It's a very thick book, and taks some getting used to, but so far it's been very helpful to me.
I've got that one, it's pretty good. Also use Beginning VB.Net, 2nd ed., and Murach's VB.Net database programming .
I know VB 6, self teaching VB.Net, as well as VBA, php, MySql, FilePro (an old DOS db) at the same time. Sometimes I get 'em mixed up
-
May 28th, 2004, 03:13 PM
#13
yay gay
Well, in VB.NET using sender.<some radiobutton property> will work because VB.NET allows late binding. But in C# for example you can only use methods/properties from sender's type (object), if you want to use radiobutton's one you will have to do casting first.
In C# you will have to use casting if you want to use sender as an RadioButton. Vb.Net will allow you to do for example sender.LOL(), and even compile without raising any error.
Now run the app..Wow! An error! That's the bad part about late binding - the compiler CAN'T know if you are trying to access something that doesn't exist or not.
And if you are using a big loop that is resource intensive it will have to each time check what kind of object it is before calling the method/property you want, making your application lots slower.
Last edited by PT Exorcist; May 28th, 2004 at 03:16 PM.
\m/  \m/
-
May 28th, 2004, 03:41 PM
#14
Originally posted by PT Exorcist
Well, in VB.NET using sender.<some radiobutton property> will work because VB.NET allows late binding. But in C# for example you can only use methods/properties from sender's type (object), if you want to use radiobutton's one you will have to do casting first.
In C# you will have to use casting if you want to use sender as an RadioButton. Vb.Net will allow you to do for example sender.LOL(), and even compile without raising any error.
Now run the app..Wow! An error! That's the bad part about late binding - the compiler CAN'T know if you are doing **** or not and if you are using a big loop that is resource intensive it will have to each time check what kind of object it is before calling the method/property you want, making your application slower
Piggy-backing on what PT said, VB.NET will allow you to late bind as long as OPTION STRICT is off (which it is by default). If you turn OPTION STRICT on, you MUST cast it before accessing the sender's properties.
TG
-
May 28th, 2004, 09:49 PM
#15
Yes VB.NET with Option Strict on has the same rules as C#.
The casting issue has to be with inheritance, you see the sender can be and is (you assume) in this case a RadioButton but it is also an Object. All objects derive or inherit from the base type Object. So then you have a situation where all poodles are dogs but not all dogs are poodles. All RadioButtons are objects but not all objects are RadioButtons. Anything can be passed as the sender since it takes the type Object. RadioButton gets passed because it is raising the event. Sender is always (almost) the object that raised or caused the event to fire. Since you only have one type of control handling that event then you are pretty sure that sender will be a RadioButton. This is not always safe as you could just call the method in code: RadioButton1_Click(Me,Nothing) and pass something else as the sender in which cause you'd get an error. So really you should check the type before casting.
Casting converts a type to another type, so long as both types are in the same inheritance chain. In other words since RadioButton inherits from Object you can cast object to RadioButton. RadioButton also inherits from Control so does ListBox. Never the less since RadioButton doesn't inherit from ListBox if listbox got passed to your click event as type Object it could not be cast to RadioButton but it could be cast to Control. I hope that makes sense.
Casting allows the compiler to check for errors at designtime and should always be used otherwise as PT mentioned you get funky stuff at runtime.
Also TabIndexes are relative to their container. So when you see that multiple controls have the same TabIndex its because they are in different containers. This is shown in the TabOrder view by something like this: 2.1, 2.2, 3.1 with the Containers TabIndex followed by the control's tabindex.
-
May 29th, 2004, 09:44 AM
#16
Frenzied Member
Thanks Edneiss, that's pretty much what I thought originally, although you explained it much better. So although you (normally) wouldn't have to cast, it's safer to do so, and may be required in some cases.
I still don't like using tabindexes to check most controls (tabcontrol may be an exception). I know it'll work most of the time, but I wouldn't have faith in it. I've worked on modifying 100k+ lines of code spread across multiple files (with no commenting or documentation anywhere) in Delphi, a kind of VB in Pascal, and it's really hard. You can make your changes and the modification will work right, but it screws up something else. So you have to test (or the customer does!) the whole app each time. Then when it doesn't, you pretty much have to step through hundreds of lines of code to figure out where the problem is. Fix that, and you're faced with the same problem. There was one sub that dozens of other subs called, and it did different stuff for them all. So any change, which almost had to use that sub, affected everything else. A huge pain & flaw.
I know that's a function of the original software design, or lack of it, but most companies aren't going to redesign a whole system if they're still making money off of it.
I know none of us here would do that
I'm a big fan of short, simple subs/functions. A rule of thumb I use is that if the sub won't fit on a screen, consider breaking it up. Long subs that do a lot may be a bit faster than making a bunch of calls to other subs, but the benefits aren't worth it But we know that, right? At least that's my design strategy.
-
May 29th, 2004, 01:12 PM
#17
"although you (normally) wouldn't have to cast, it's safer to do so"
Actually you should always cast. Even if you don't then the compiler will still have to at runtime which on top of possible errors will be a performance hit because it will have to figure out what to cast it to at that time. I mean will your code work without casting - sometimes, but that doesn't mean you shouldn't do it.
Of course this is just my personal opinion.
-
May 29th, 2004, 01:23 PM
#18
Frenzied Member
Well if the compiler does so at runtime anyway, does the explicit cast just duplicate it?
One thing I'd like to see in the documentation for all languages is the order in which events are called.
Edneiss, you ought to write a texbook. You explain things to us doofuses very well.
-
May 29th, 2004, 03:17 PM
#19
No it doesn't duplicate it because if you cast it then the properties will match the type.
It goes like this:
The compiler reaches this point: sender.Name and says huh? sender is of type object and object does not have a name property so now I have to figure out what the hell this programmer meant by this line of code. Then it tries to go through the inheritance chain of that type for something that has a Name property. If it finds one it uses it otherwise it throws an exception. Then it says damn that was a lot of work I think I'll knock off for a while and go get a beer.
Now with casting it reaches this point: DirectCast(sender,RadioButton).Name and it says oh I need to convert this to a RadioButton and then continue executing the line of code. Then it checks and says hey this object can convert to RadioButton. That was easy now the property Name matches to the type RadioButton and everyone is happy. Then it says wow that was easy I'm ready for more, bring it on!
Of course I may be paraphrasing some of that but you get the idea. 
Here is a more codewise example. Using the following code:
VB Code:
Private Sub btnLateBinding_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnLateBinding.Click
'late binding
MsgBox(sender.text)
End Sub
Private Sub btnStrongTyped_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnStrongTyped.Click
'strong typing or early binding
MsgBox(DirectCast(sender, Button).Text)
End Sub
This is what Reflector decompiles it to:
VB Code:
Private Sub btnLateBinding_Click(ByVal sender As Object, ByVal e As EventArgs)
Begin Sub
Interaction.MsgBox(RuntimeHelpers.GetObjectValue(LateBinding.LateGet(sender, Nothing, "text", New Object((0) - 1) {}, Nothing, Nothing)), 0, Nothing)
End Sub
Private Sub btnStrongTyped_Click(ByVal sender As Object, ByVal e As EventArgs)
Begin Sub
Interaction.MsgBox(CType(sender,Button).Text, 0, Nothing)
End Sub
And this is the IL for the different ways:
VB Code:
Private Sub btnLateBinding_Click(ByVal sender As Object, ByVal e As EventArgs)
.maxstack 8
L_0000: nop
L_0001: ldarg.1
[b]L_0002: ldnull
L_0003: ldstr "text"
L_0008: ldc.i4.0
L_0009: newarr Object
L_000e: ldnull
L_000f: ldnull
L_0010: call LateBinding.LateGet
L_0015: call RuntimeHelpers.GetObjectValue[/b]
L_001a: ldc.i4.0
L_001b: ldnull
L_001c: call Interaction.MsgBox
L_0021: pop
L_0022: nop
L_0023: ret
Private Sub btnStrongTyped_Click(ByVal sender As Object, ByVal e As EventArgs)
.maxstack 8
L_0000: nop
L_0001: ldarg.1
[b]L_0002: castclass Button
L_0007: callvirt Control.get_Text[/b]
L_000c: ldc.i4.0
L_000d: ldnull
L_000e: call Interaction.MsgBox
L_0013: pop
L_0014: nop
L_0015: ret
Last edited by Edneeis; May 29th, 2004 at 03:26 PM.
-
May 30th, 2004, 09:48 PM
#20
Frenzied Member
Edneiss rules, man. I'm not a complete dolt, I've learned to various degrees VB6, C++, Java, Perl, VBA, VB.Net,Delphi, perl, php, and he can cut through the crap and show what's what.
-
Jun 1st, 2004, 07:27 AM
#21
Thread Starter
Frenzied Member
Edneeis ... Savelinus ...
Wow! All due respects to Edneeis ... on 5/28 he stated "when you see that multiple controls have the same TabIndex it's because they are in different containers". In VB.Net multiple controls in the SAME container may be assigned (by the designer) the SAME TabIndex. I saw a reference that said if this is the case, the actual tab order is resolved by the Z order (?) (relative position?).
Savelinus ... deleting a control does NOT affect the TabIndex of other controls in the container. I tested this with a panel of 5 Radio Buttons, originally with a tab order sequence of 0 - 4. I changed the 4th control to a TabIndex of 2, and deleted the 2nd control. I ended up at Run Time with the following:
RadioButton1 TabIndex = 0
RadioButton3 TabIndex = 2
RadioButton4 TabIndex = 2
RadioButton5 TabIndex = 4
Thanks again for everybody's help.
Blessings in abundance,
All the Best,
& ENJOY!
Art . . . . Carlisle, PA . . USA
-
Jun 1st, 2004, 09:43 PM
#22
Originally posted by Webtest
Wow! All due respects to Edneeis ... on 5/28 he stated "when you see that multiple controls have the same TabIndex it's because they are in different containers". In VB.Net multiple controls in the SAME container may be assigned (by the designer) the SAME TabIndex. I saw a reference that said if this is the case, the actual tab order is resolved by the Z order (?) (relative position?).
Thats good to know. Thanks.
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
|