sub functions vs event, what is the difference? - vb.net

I went through events in Vb.net and i found they are really an amazing feature..but still confused about how to use them effectively.
The real doubt is that the functions and sub could be effective alternative for events. Whatever i do with events i can manage to do it via functions and methods. Wherever there is Raisevent, i can substitute it with a function or procesure. so then, what is the real benefit of events and in which cases i can use them instead of functions and procedures?

Let's see if you understand it with an example. You have the Button control. It defines a lot of events (Click,MouseDown,Keypress...). When you put a button in a Form, you decide there what are the events you want to manage. So in the form you can do something when a button is clicked, or not doing anything.
Imagine if this was done with regular methods. In that case, the button should have a reference to the form where the button is, and the form should have a Click method, is it using it or not.
The event driven programing makes very easy to define some Events to signal when something happens in a class, and is the class that creates the instance the one that decides if that event is relevant or not.

thank you for clarification, I got the point. The point I Missed was that : event is fired in the same class, but execution is done in a different class.
I mean, when I define a class, I can put RaiseEvent somewhere to recognize something, but I correlate the event with a sub in a different class.
so, in such a class called Wallet I can put a statement like :
If Dollars > 5 Then
RaiseEvent Above5()
End If
and in such different class called AllWallet :
Dim WithEvents myWallet as new Wallet
Sub myWallet_Above5() Handles myWallet.Above5
MsgBox("Dollars are more than 5")
End Sub
otherwise, I mean if events are fired in the same class they are defined in , the sub and functions can substitute events.
thanks to all

Related

Programming method

When I am programming in VB.net, I usually use a normal methodology (I think).
When I have a form, and some buttons placed on it, and some functions under this buttons, I implement the functionality of this buttons in the moment the button is pressed, for example:
I press a button, inside the button I use nested If..else structure to do something in order of a given condition. When the condition is true, I obtain a specific result.
I have heard (and I am not able to find information) about another methodology, where this if..else structure is not done each time you press the button, but the structure only executes one time, and not need to pass throught the if..else structure more times. Is like the program knows the solution without doing this structure all the times the button is pressed. Only needs to do it the first one.
I don't know if someone understand my question, but if someone knows about what I am talking and could give me some useful information, I would be very grateful!
i don't even know if this methodology exists, but I heard about it and I would like to investigate..
I am investigating about the performance of the programs I am creating..
You can add a member-level variable to detect if the button click handler code has been executed.
Public Class Form1
Private isInitialized As Boolean
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
'Do some stuff if this is the first time the button was clicked.
If Not isInitialized Then
'do some stuff...
isInitialized = True
End If
'Do some other stuff each time the button is pressed.
'do some stuff...
End Sub
End Class
Thanks for your answers!
Finally I understood how the methodology I've heard works.
It is quite simple, but my question was not well made, so now I know that my answer is too vague.
I didn't know, because of my few experience programming controls, that I can made my own control which I can use in my forms. With this, I can paint this control in the way I want. I am going to put an example that answer the problem I had:
A control that will be a clock, and this clock can be analogic or digital. Before I knew this, I had a button named 'Change Clock' which change the appareance of the clock between analogic and digital. And when I press that button, in the click event of the button, I start to paint the clock, either is analogic or digital.
Now I know that programming controls, I am able to made a control by creating a UserControl in my project, and inside the code of this new control I can use the paint event to paint the clock in order of a property. Something like this:
Private Sub AnalogClock_Paint(sender As Object, e As PaintEventArgs) Handles MyBase.Paint
Select Case m_contenido
Case formatoReloj.analogico
'Paint analogic clock
Case formatoReloj.digital
'Paint digital clock
End Select
End Sub
and when I use this control in my form, I only need to change the property of the clock and not to paint everything each time I want to change it. That means that is already painted in the code of the control and I have not to use code in my form to do it..
I hope you understand now what I wanted..

vb.net winform from a usercontrol call a function on the parent form

I don't know how to put it right, but I have a vb.net winform app in which I want to use a customcontrol so I can re-use the logic on multiple forms. I know how to set values in this control from the parent (using properties in the control). But now I want to call a specifiek function on the parent form. Im my case LoadData() which is a procedure of the parentform. How can I do this?
I know I can reference the parent form by using Me.ParentForm in the usercontrol. But I cannot call the LoadData() procedure in the parentform.
Any help? This is a winforms app, not a ASP.NET app.
T.I.A.
[Edit]
I could solve my problem using this example found right here. This is working fine
First, a UserControl is for reusing GUI logic, so I hope that is what you meant. If you are trying to reuse non-GUI logic you might want to create some stand-alone classes for that.
Second, it is generally bad design to call back up to the parent form in the way you describe because it makes the UserControl less reusable and it creates an overly tight binding between the two. You should, if at all possible, push the data down into the UserControl instead.
If you can find no way for the Form to push the data down (perhaps because it is based upon a UI interaction within the UserControl), you have a couple of other options. The first is to wrap up the data-loading behavior into an object that can be passed to the UserControl during initialization, and the the UserControl can access the LoadData method on it as needed. Another approach is to have the UserControl define a set of Events that can be used to request external data from the form. I like to use the "Query" prefix on these kinds of events. So when a fetch button is tapped on your UserControl, it raises the "QueryData" event, and the form that is handling that event responds by populating a data container of some sort that is part of the custom EventArgs.
Either of these can be expanded upon if you need more assistance.
Upon re-reading the question, I it looks like perhaps my approach is over kill. I was under the impression that the LoadData was a method in the Form that loaded data into the UserControl. If it is just a simple call then focus on the event portion of my answer and ignore the data container portion.
I would add an event to your control and handle it on the form the control is part of.
In your control, put something like this:
Public Event LoadData(ByVal sender As Object, ByVal e As System.EventArgs)
And in your form, you can have something like this:
Private Sub UserControl1_LoadData(sender As Object, e As EventArgs) Handles UserControl1.LoadData
'...Your code here
End Sub

Is there any way to clear subscription to an event in VB.NET?

In C#, I took the habit on clearing every subscriptions to my custom events in Dispose() to avoid memory leaks of subscribers forgetting to unsubscribe from my events.
It was very simple to do, simply by calling MyEvent = null since the C# compiler automatically generates a delegate field. Unfortunately in VB.NET, there seems to be no simple way to do this. The only solution I came up with was to write a Custom Event, adding custom add and remove handlers calling Delegate.Combine / Delegate.Remove, basically what the C# compiler does. But having to do this for every event just to be able to clear the subscriptions seems a little 'overkill' to me.
Does anyone have another idea to solve this problem? Thanks.
It's exactly the same in VB.Net. The compiler automatically creates a delegate field for each event, just like the C# compiler, but in VB the field is hidden. However you can access the variable from your code - it's always named XXXEvent, where XXX is the event name.
So you can easily clear subscriptions to the event, just like in C#:
Public Class Class1
Implements IDisposable
Event MyEvent()
Sub Clear() Implements IDisposable.Dispose
Me.MyEventEvent = Nothing ' clear the hidden variable '
End Sub
End Class
I'm also thinking it should be possible to use reflection to automatically find all the hidden delegate variables, and clear them. Then they don't have to be listed in the Clear method.
I've got only vague knowledge of VB.NET, but what about AddHandler / RemoveHandler?

VB.NET 2005 - "Global" Event Handler?

Suppose that for every Form in a WinForms application, you want to change the cursor to the WaitCursor. The obvious way to do this would be to add the code to every place where a form is instantiated/shown:
Try
Me.Cursor = Cursors.WaitCursor
Dim f As New frmMyForm
f.Show()
Catch ex As Exception
Throw
Finally
Me.Cursor = Cursors.Default
End Try
However, I was wondering if there is a way to tell your application, "Whenever any form Load event fires, show a WaitCursor. When the form event Shown is complete, set the cursor back to Default." This way, the Me.Cursor code could be only in one place and not scattered throughout the application - and not forgotten to put it in to each form instantiation.
I suppose you could subclass the regular Form class and add the cursor settings in an overridden event, but I believe you lose the visual designer capability when you subclass the Form object.
Subclassing is an option, you don't loose the designer as long as you don't set the superclass as mustinherit, it doesn't really like that.
To answer your question - there are no global .Net events to achieve what you want. There isn'y any pure .net solution to this. You could take a look at Aspect Orientated Programming and Cross Cutting Concerns - there may be an AOP solution to this (some googling will get you started then post back here for details).
However, what follows is more of an idea rather than a complete solution as to how you might achieve this using win32 messaging.
You need to work out which win32 messages correspond to the Load event and if there is a win32 message that always happens after the load event. One candidate for the load event might be WM_SHOWWINDOW but I'm not sure.
Write a message filter class (i.e. implement IMessageFilter).
In the message filter class's PreMessageFilter method check the message type and if it is a WM_SHOWWINDOW (or whatever) message with the correct paramters then you can set/reset the cursor (using Cursor.Current = Cursors.WaitCursor - again you need to test this)
Another option that wouldn't involve subclassing is to add an extension method to the Form type. Then you could just call your extension method (something like ShowAndWait()) instead of show. You might even be about to call is Show if you overload it with a different signature.

Force multi-threaded VB.NET class to display results on a single form

I have a windows form application that uses a Shared class to house all of the common objects for the application. The settings class has a collection of objects that do things periodically, and then there's something of interest, they need to alert the main form and have it update.
I'm currently doing this through Events on the objects, and when each object is created, I add an EventHandler to maps the event back to the form. However, I'm running into some trouble that suggests that these requests aren't always ending up on the main copy of my form. For example, my form has a notification tray icon, but when the form captures and event and attempts to display a bubble, no bubble appears. However, if I modify that code to make the icon visible (though it already is), and then display the bubble, a second icon appears and displays the bubble properly.
Has anybody run into this before? Is there a way that I can force all of my events to be captured by the single instance of the form, or is there a completely different way to handle this? I can post code samples if necessary, but I'm thinking it's a common threading problem.
MORE INFORMATION: I'm currently using Me.InvokeRequired in the event handler on my form, and it always returns FALSE in this case. Also, the second tray icon created when I make it visible from this form doesn't have a context menu on it, whereas the "real" icon does - does that clue anybody in?
I'm going to pull my hair out! This can't be that hard!
SOLUTION: Thanks to nobugz for the clue, and it lead me to the code I'm now using (which works beautifully, though I can't help thinking there's a better way to do this). I added a private boolean variable to the form called "IsPrimary", and added the following code to the form constructor:
Public Sub New()
If My.Application.OpenForms(0).Equals(Me) Then
Me.IsFirstForm = True
End If
End Sub
Once this variable is set and the constructor finishes, it heads right to the event handler, and I deal with it this way (CAVEAT: Since the form I'm looking for is the primary form for the application, My.Application.OpenForms(0) gets what I need. If I was looking for the first instance of a non-startup form, I'd have to iterate through until I found it):
Public Sub EventHandler()
If Not IsFirstForm Then
Dim f As Form1 = My.Application.OpenForms(0)
f.EventHandler()
Me.Close()
ElseIf InvokeRequired Then
Me.Invoke(New HandlerDelegate(AddressOf EventHandler))
Else
' Do your event handling code '
End If
End Sub
First, it checks to see if it's running on the correct form - if it's not, then call the right form. Then it checks to see if the thread is correct, and calls the UI thread if it's not. Then it runs the event code. I don't like that it's potentially three calls, but I can't think of another way to do it. It seems to work well, though it's a little cumbersome. If anybody has a better way to do it, I'd love to hear it!
Again, thanks for all the help - this was going to drive me nuts!
I think it is a threading problem too. Are you using Control.Invoke() in your event handler? .NET usually catches violations when you debug the app but there are cases it can't. NotifyIcon is one of them, there is no window handle to check thread affinity.
Edit after OP changed question:
A classic VB.NET trap is to reference a Form instance by its type name. Like Form1.NotifyIcon1.Something. That doesn't work as expected when you use threading. It will create a new instance of the Form1 class, not use the existing instance. That instance isn't visible (Show() was never called) and is otherwise dead as a doornail since it is running on thread that doesn't pump a message loop. Seeing a second icon appear is a dead give-away. So is getting InvokeRequired = False when you know you are using it from a thread.
You must use a reference to the existing form instance. If that is hard to come by (you usually pass "Me" as an argument to the class constructor), you can use Application.OpenForms:
Dim main As Form1 = CType(Application.OpenForms(0), Form1)
if (main.InvokeRequired)
' etc...
Use Control.InvokeRequired to determine if you're on the proper thread, then use Control.Invoke if you're not.
You should look at the documentation for the Invoke method on the Form. It will allow you to make the code that updates the form run on the thread that owns the form, (which it must do, Windows forms are not thread safe).
Something like
Private Delegate Sub UpdateStatusDelegate(ByVal newStatus as String)
Public sub UpdateStatus(ByVal newStatus as String)
If Me.InvokeRequired Then
Dim d As New UpdateStatusDelegate(AddressOf UpdateStatus)
Me.Invoke(d,new Object() {newStatus})
Else
'Update the form status
End If
If you provide some sample code I would be happy to provide a more tailored example.
Edit after OP said they are using InvokeRequired.
Before calling InvokeRequired, check that the form handle has been created, there is a HandleCreated property I belive. InvokeRequired always returns false if the control doesn't currently have a handle, this would then mean the code is not thread safe even though you have done the right thing to make it so. Update your question when you find out. Some sample code would be helpful too.
in c# it looks like this:
private EventHandler StatusHandler = new EventHandler(eventHandlerCode)
void eventHandlerCode(object sender, EventArgs e)
{
if (this.InvokeRequired)
{
this.Invoke(StatusHandler, sender, e);
}
else
{
//do work
}
}