I've created a VB.Net application which consists of a form and a series of classes. One class (GUI) contains all of the routines that handle the logic associated with the controls on my form. These controls are placed at design time.
I've having a problem with a couple of the timers on the form. They are declared in the GUI class thus:
Private WithEvents timerScreenUpdate As Timer
Private WithEvents timerDebug As Timer
but I'm getting an error in this line:
Private Sub timerScreenUpdate_Tick(sender As System.Object, e As System.EventArgs) Handles timerScreenUpdate.Tick
The error is "Event 'Tick' cannot be found". I'm getting the same error for the other timer.
It's probably related but I'm also getting a similar error in this line:
Private Sub Monitor_FormClosing(sender As Object, e As FormClosingEventArgs) Handles MyBase.FormClosing
which is "Event 'FormClosing' cannot be found".
How can I make these events visible to my class ?
Make sure that the reference and the Namespace-Import of System.Windows.Forms is available in your project respectively class file.
Without it, VB will use a Timer from the namespace System.Timers which you don't want to use in your case.
Related
I am pretty a beginner in using visual studio so I may missed a lot of things. I want to create a custom group in MS Project with a button which I want when I click on it, it would open up a WinForm with some buttons on it. So I created a VSTO project for MS project then added a Ribbon(Visual designer) and a form.
My custom group in Task tab created with a button in it. I double clicked on this button to jump right into it's click handler code, then tried to write a simple code to show my form but it seems it lacks something because intellisense doesn't show up .Show() method and it can not be built. The error I got when I try to build is this:
error BC30469: Reference to a non-shared member requires an object reference.
My form label is Form1 and the simplest code which I wrote in my button click event handler is as follow:
Imports Microsoft.Office.Tools.Ribbon
Imports System.Windows.Forms '(I added this line after the hints)
Public Class Ribbon1
Private Sub Ribbon1_Load(ByVal sender As System.Object, ByVal e
As RibbonUIEventArgs) Handles MyBase.Load
End Sub
Private Sub Button1_Click(sender As Object, e As
RibbonControlEventArgs) Handles Button1.Click
Form1.Show() '(The Line which error occurs)
End Sub
End Class
First of all, you need to check references of your add-in project. By default VSTO add-in projects don't include the System.Windows.Forms assembly reference. If the reference is not there, you need to add it manually. Then in the code you need to use the fully qualified namespace or include it in the beginning of the code file (by using the Imports keyword).
To be able to call the Show method you need to create the Form1 instance in the code first. The method is not static, so you can't invoke it on the class declaration. You must have an object reference.
The code may look like that:
Private Sub Button1_Click(sender As Object, e As
RibbonControlEventArgs) Handles Button1.Click
Dim f as Form1 = new Form1()
f.Show()
End Sub
I want to fire an event in another class.
And my problem is I don't know how to make it.
I'm trying to use Inherits statement to my Form and add my class name to it, and it works as I hope:
Public Class Frm_Main_Copy
Inherits ToolStripMenuApp
'I have a ToolStripMenu that has declared before on my class and it sounds like this:
'Public Shared WithEvents Cat000x86_64App As ToolStripMenuItem
...
Private Sub IsClicked(ByVal sender As Object, ByVal e As EventArgs) Handles Cat000x86_64App.Click
End Sub
End Class
but the designer form messed up(returns a fatal error) and I should delete the Inherits statement, and the others.
Tried to act as form designer script(Trying to put this code to my class):
Friend WithEvents BlahBlah As RadioButton 'For example
It didn't worked,
Declaring a variable for my class and It didn't worked too
Searched on the Internet and it seems likely more complicated than I thought...
Anyone can help? Any help is appreciated.
A form is not a form unless it inherits, either directly or indirectly, the Form class. You cannot inherit any type that is not itself a form and expect your type to be a form. With that code, if ToolStripMenuApp is not a form then Frm_Main_Copy is not a form either, hence no form designer.
If what you're actually saying is that you have an instance of that ToolStripMenuApp that contains a TooStripMenuItem whose Click event you want to handle in Frm_Main_Copy then the first step is to not declare Cat000x86_64App as Shared. Frm_Main_Copy needs to declare a method capable of handling that event:
Private Sub IsClicked(ByVal sender As Object, ByVal e As EventArgs)
'...
End Sub
Note that there is no Handles clause because there's no WithEvents variable in that class whose event you are handling.
Next, Frm_Main_Copy must have access to the appropriate instance of ToolStripMenuApp. It's impossible for us to say how best to do that based on the information provided but it might be as simple as this:
Dim tsma As New ToolStripMenuApp
You then register your method as a handler for the appropriate event:
AddHandler tsma.Cat000x86_64App.Click, AddressOf IsClicked
If you use AddHandler, make sure to use RemoveHandler when you're done with either object. I suggest that you do some reading based on this information.
I'm relatively new to Windows Forms development and my first real application has reached a point where a lot of code starts to build up in my main Form file, so I decided to restructure my project using the MVC pattern.
One major problem I have is dealing with the different control events of the form. I have several buttons, textfields, comboboxes and also a tabcontroll element which again contains different input elements and so far, every procedure for handling clicks, updates and other changes is defined in my main class.
For example:
Private Sub btnOk_Click(sender As Object, e As EventArgs) Handles btnOk.Click
some code...
End Sub
So my question is: what would be the best way to handle these events outside of my main form? I'm more familiar with building GUIs in Java where you can use ActionListeners to achieve this but I have found nothing similar for my work with Windows Forms.
To subscribe to a Control event outside of your main form class, make your control public, so you can access from another class). This can be done using the Modifier property at design-time. Then, use the AddHandler keyword to subscribe to any event programmatically.
After researching a bit more, I found that there is probably not THE correct answer to this problem but I found 2 approaches which provide a solution in the way I was looking for. In both cases, I use a controller class which is responsible for handling any user interaction from my main form.
The first approach makes use of what DmitryBabich suggested, adding a handler to the object and referencing it to a method of my controller class:
in Form1:
Dim ctrl as new Controller(Me)
AddHandler Button1.Click, AddressOf ctrl.doSomething
Controller class:
Public Class Controller
Private myForm As Form1
Public Sub New(ByVal f As Form1)
myForm = f
End Sub
Public Sub doSomething(sender As Object, e As EventArgs)
MsgBox("Button clicked.")
End Sub
End Class
For an example this simple it is not necessary to pass an instance of Form1 over to the controller but if for example I'd like to access the values of other control elements as well, I can address them by using this instance of Form1.
For example:
Public Sub doSomething(sender As Object, e As EventArgs)
MsgBox("You clicked the button, by the way: The value of TextField1 is " & myForm.TextField1.text)
End Sub
The other approach is almost identical except that here the controller knows all the relevant user control objects of the form and can handle their events directly, meaning that in the main form I have to do nothing more than create an instance of the controller. In the controller however, I have to assign every user control I want to access to its own variable as soon as the main form is loaded:
in Form1:
Dim ctrl as new Controller(Me)
Controller class:
Public Class Controller
WithEvents myForm As Form1
WithEvents button1 As Button
WithEvents button2 As Button
Public Sub New(ByVal f As Form1)
myForm = f
End Sub
Public Sub formLoad() Handles myForm.Load
button1 = myForm.Button1
button2 = myForm.Button2
End Sub
Private Sub b1Click() Handles button1.Click
MsgBox("You clicked button1!")
End Sub
Private Sub b2Click() Handles button2.Click
MsgBox("Button #2 was clicked!")
End Sub
End Class
I have created a Form with Objects like Progressbar and Button.
I have also created Public library code outside my Form
I want to modify the Progressbar Control or the Button's Text from a Sub that is written in a library (I try to pass my Form as a parameter):
Public Shared Sub ModifyItems(ByRef _WhichForm As Form)
_WhichForm.MyProgressBar1.visible = True
End sub
Unfortunately, the code Is not recognizing the Progressbar name MyProgressBar1
Is there a way to modify the Progressbar Control on the Form directly in a Sub or Function that is written in a class library, not directly in the Form Code ?
This type of approach would generally fall under the umbrella of "bad practice". Having objects modifying each others members directly introduces tight coupling that makes for difficult code to extend, debug, and maintain.
Rather than trying to modify something from within the library, better to think in terms of notifying that something within the library has changed. You could, for example, raise an event within the library. Form1 could then listen for that event and make any changes to its components that are appropriate. This way Form1 is solely responsible for modifying its components and the library is solely responsible for announcing changes to its internal state.
To give a good example - if, say, you were to change your Form's progress bar component (maybe you find a better one out there) you suddenly introduce a breaking change into your library.
To use an event you might do something like :
Public Class MyLibrary
Event OnSomethingHappened()
Private Sub SomethingHappened()
RaiseEvent OnSomethingHappened()
End Sub
End Class
And then in your form :
Public Class Form1
Private WithEvents _myLibrary as New MyLibrary
Private Sub LibraryDidSomething() Handles _myLibrary.OnSomethingHappened
MyProgressBar1.Visible = True
End Sub
End Class
This nicely decouples any dependence on Form1 - the library exists as a self-contained entity and doesn't care who listens to its events.
If you want to do this with a shared class you can also use shared events - these must be connected programmatically as :
Public Class MyLibrary
Shared Event OnSomething()
Public Shared Sub DoSomething()
RaiseEvent OnSomething()
End Sub
End Class
in the form :
Public Class Form1
Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) _
Handles MyBase.Load
AddHandler MyLibrary.OnSomethingHappened, AddressOf LibDidSomething
End Sub
Private Sub Form1_FormClosed(sender As System.Object, e As _
System.Windows.Forms.FormClosedEventArgs) Handles MyBase.FormClosed
RemoveHandler MyLibrary.OnSomethingHappened, AddressOf LibDidSomething
End Sub
Private Sub LibDidSomething()
MyProgressBar1.Visible = True
End Sub
End Class
When programmatically adding events you must take care to remove them before disposing of the objects that have subscribed to them. In this case I have added the handler when the form loads and have removed it when the form closes. If you fail to remove an added handler then the form would not be garbage collected and this would cause a memory leak.
See here for more reading : Raising Events and Responding to Events (MSDN)
When I am selecting a button from the .xaml file and then tap event from the right (in order to set the tap event) it auto generates this sub:
Private Sub btn(ByRef sender As Object, e As System.Windows.RoutedEventArgs) Handles btn.Tap
End Sub
But it also has this error:
Error 1 Handles clause requires a WithEvents variable defined in the containing type or one of its base types.
Any suggestions? Thank you!
Public WithEvents btn As Button
just above the sub in order to send away the bug !