Copying code from Private Sub to Shared Sub - vb.net

I'm trying to have a bunch of code run on the hour every hour in my VB Application. The code works in it's own Sub, but when I add it to this "TopOfTheHour" Shared Sub I get the error "cannot refer to an instance member of a class from within a shared method or shared member initializer without an explicit instance of the class"
I left in the loadlbl.Visible as an example of what doesn't work which is just a label control on my main Form (Form1). Writing the refresh time to the console works, but loadlbl.Visible = True does not.
Private Shared Sub OnTimedEvent(source As Object, e As System.Timers.ElapsedEventArgs)
Dim aTimer As System.Timers.Timer = CType(source, System.Timers.Timer)
aTimer.Stop()
Console.WriteLine("Server Status Refreshed at " & DateTime.Now)
loadlbl.Visible = True
'Far more code is here, much of it with the same error.
aTimer.Interval = MillisecondsToNextTopOfTheHour()
aTimer.Start()
End Sub
All my code for Form 1 (including what I want to add to this Shared Sub) is here on PasteBin. (VB Syntax Highlighting is on so code is easier to read)
Thank You!

Do you really need this method to be 'shared'? Remove the shared and try again.
Shared means that is method is not an instance method, it has no access to any local variables.

Related

How can i call my function from my main form in another form without this error in vb.net

I am currently developping an app WinForm using vb.net and i have to call a function, situated in my main form, in another form. Here is my function in my main form
Public Sub ImprimCalibrage(t1 As String, t2 As String)
Dim strCalibr As String = Build_str("CAL", "CALIBRAGE", t1, t2)
BuildFile("fileT.txt", strCalibr)
Print()
End Sub
To call it, i have created an attribute in my secondary form like this
ReadOnly form1 = Application.OpenForms("Main")
And now i call my function doing this form1.ImprimCalibrage(TextBox1.Text, TextBox2.Text)
But when i click on the button which supposed excute the function, i got this error
'Object variable or With block variable not set.'
I don't have any idea how to solve it because i dont have with block and my only variable in just a String.
Application.OpenForms("Main") is returning Nothing because at the time it is called (when Form2 is created) , there is no open form named Main in the collection. This Nothing then persists until you try and use it. You can't call a method on Nothing. Even if you later ensure there is a form named Main in the OpenForms collection, it doesn't alter the fact that at the time you looked (and captured) there was nothing
Move the code to just before you need it
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim form1 As Form1 = Application.OpenForms("Main")
form1.ImprimCalibrage(TextBox1.Text, TextBox2.Text)
End Sub

How to call a sub within anohter sub that is on a different form. VB.NET

I'm self taught so pardon me if my terminoligy isn't correct.
I want to call a sub within another sub that is in a completely different form. but for some reason i can't get it to work. Maybe it's not possible. I'm not sure.
for a bit of background on the program. There's two pictureboxes. One has a binding source and the other does not. I want the one that doesnt have a binding source to display the same image as the other picture box once it has loaded.
so the first sub is in form2. code is as follows:
Public Sub GetImage()
Me.Pbox_Image.Image = Mainfrm.Pbox_Image.Image
Me.Pbox_Image.Refresh()
Me.Pbox_Image.Update()
End Sub
This procedure works fine when called within form2. But i want the code to run when mainfrm p_Imageload is completed.
The code I used in mainfrm is as follows:
Public Sub Patient_Image_LoadCompleted(sender As Object, e As AsyncCompletedEventArgs) Handles Patient_Image.LoadCompleted
GetImage()
End Sub
Visual studio displays an error and the code will not run. The error says that GetImage is not declared. I thought setting it to public would solve the issue but it didn't.
Any help is greatly appreciated.
You call it with adding a containing class infront of method, like this:
On FormX:
Sub
FormY.MethodZ()
End Sub

Update control on main form via Background Worker with method in another class VB.Net

I have been banging my head against the wall all day trying to figure this one out.
I am finishing up a program to simply delete files in specific temp folders. I have read that it is sometimes good practice to create separate classes for methods and variables. So I have created a separate class for a couple methods to delete files and folders in a specified directory. I am using a Background Worker in my Form1 class and am calling my deleteFiles() method from my WebFixProcesses class in the DoWork event in the Form1 class. I am using a Background Worker so that I can easily report progress back to a progress bar on my main form.
The files get deleted without an issue but I just can't get the label on my main form to reflect the current file being deleted. the label doesn't change in any way.
I know the formula is correct as I can get this working if the method is in the Form1 class. and I simply use:
Invoke(Sub()
lblStatus.Text = File.ToString
lblStatus.Refresh()
End Sub)
here is my method that I am calling from the WebFixProcesses class:
Public Shared Sub deleteFiles(ByVal fileLocation As String)
For Each file As String In Directory.GetFiles(fileLocation)
Try
fileDisplay.Add(file)
For i = 1 To fileDisplay.Count
file = fileDisplay(i)
Form1.BackgroundWorker1.ReportProgress(CInt(i / fileDisplay.Count) * 100)
Next
IO.File.Delete(file)
Form1.labelText(file)
Form1.labelRefresh()
Catch ex As Exception
MessageBox.Show(ex.Message)
End Try
Next
End Sub
labelText() and labelRefresh() are methods from my main form which are using delegates to try to pass information to the control:
Public Sub labelText(ByVal file As String)
If lblStatus.InvokeRequired Then
Dim del As New txtBoxDelegate(AddressOf labelText)
Me.Invoke(del, file)
Else
lblStatus.Text = file.ToString()
End If
End Sub
Public Sub labelRefresh()
If lblStatus.InvokeRequired Then
Dim del As New txtBoxRefDelegate(AddressOf labelRefresh)
Me.Invoke(del)
Else
lblStatus.Refresh()
End If
End Sub
If anyone can help me out to inform me what I may be doing wrong it would be immensely appreciated as my head is in a lot of pain from this. And maybe I am going at it all wrong, and just being stubborn keeping my methods in their own class. But any help would be awesome. Thanks guys!
What Hans wrote on the question comment is true: Form1 is a type, not an instance, but to make things easier to newbye programmes (coming from VB6), M$ did a "mix", allowing you to use the form name as the instance of the form in the main thread.
This however works only if you are on that thread.
If you reference Form1 from another thread, a new instance of Form1 is created.
To solve the issue, add this code to the form:
Private Shared _instance As Form1
Public ReadOnly Property Instance As Form1
Get
Return _instance
End Get
End Property
We will use this property to store the current instance of the form. To do so, add this line to the Load event:
Private Sub Form1_Load(sender As Object, e As System.EventArgs) Handles Me.Load
_instance = Me
'other code here
End Sub
Now, from every class, in any thread, if you use
Form1.Instance
...you get the actual form. Now you can Invoke, even from the same form:
Me.instance.Invoke(Sub()
Me.lblStatus.Text = "Hello World"
End Sub)

Delegates not working in another module

Running into an odd issue with tasks and delegates. Code in question is running under dotNET 4.5.1, VS2013. On the form's code I have a sub that updates a grid, it checks to see if an invoke is required, and if it is it calls a delegate. When a task runs that's called in the same module, it works as expected, no problems. Threaded or not, the grid updates properly.
However, if the same thing is called from another module, the delegate never gets called and the visual component doesn't get updated. Just a watered down bit of pseudocode to clarify..
In the form's module:
Private Delegate Sub DoWhateverDelegate(ByVal _____)
Public Sub DoWhatever(ByVal _____)
If MyComponent.InvokeReqired
Dim Delegated As New DoWhateverDelegate(AddressOf DoWhatever)
Debug.Print("The delegate fired")
Invoke(Delegated, _____)
Else
' .. carry on as usual ..
End If
End Sub
Elsewhere....
Task.Run(Sub()
' .. various things I'd rather not block the UI thread with ..
DoWhatever()
End Sub)
Works fine. I can do Task.Run__ that calls DoWhatever and it's all happy and good. However if I create a task in another module and call DoWhatever, it doesn't fire the delegate and that visual component doesn't update. The code is identical, in the same module it works, in another module it does not.
I'm probably missing something blatantly obvious.. anyone care to point out my mistake? Thanks.
Edit -- just to clarify, that other module is just code, there's only one form in the entire solution. It's created at program startup automatically, there is no other form creation going on.
Should be a thread-specific issue. Check this:
Public Class Form1
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
foo.DoSomething()
End Sub
End Class
The class with the delegate:
Public Class foo
Public Shared Sub DoSomething()
Task.Run(Sub() UpdateText())
End Sub
Public Delegate Sub UpdateTextDelegate()
Public Shared Sub UpdateText()
Dim f = Form1
'Dim f As Form1 = Application.OpenForms("Form1")
If f.InvokeRequired Then
Dim d As UpdateTextDelegate = AddressOf UpdateText
f.Invoke(d)
Else
f.TextBox1.Text = "Hi"
End If
End Sub
End Class
Run the code and the textbox will not be updated. Use the second f=.... (that one that take a reference from OpenForms) and it will be updated.
If you just try to access the default instance and you are outside the UI-thread, a new instance of the form will be created. That means, the content IS updated, but because that form is not shown, you will not see it.
NOTE I do NOT advise to solve your problem, by using OpenForms. I'd advise to correctly instantiate forms!
Add a new module/class to your code:
Module Startup
Public MyForm1 As Form1
Public Sub main()
MyForm1 = New Form1
Application.Run(MyForm1)
End Sub
End Module
Go to project properties -> application. Disable application framework and choose Sub Main as your start object. In the app, access your form via MyForm1 - or whatever you want to name it. Problem should be gone then.

"make single instance application" what does this do?

in vb 2008 express this option is available under application properties. does anyone know what is its function? does it make it so that it's impossible to open two instances at the same time?
does it make it so that it's impossible to open two instances at the same time?
Yes.
Why not just use a Mutex? This is what MS suggests and I have used it for many-a-years with no issues.
Public Class Form1
Private objMutex As System.Threading.Mutex
Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
'Check to prevent running twice
objMutex = New System.Threading.Mutex(False, "MyApplicationName")
If objMutex.WaitOne(0, False) = False Then
objMutex.Close()
objMutex = Nothing
MessageBox.Show("Another instance is already running!")
End
End If
'If you get to this point it's frist instance
End Sub
End Class
When the form, in this case, closes, the mutex is released and you can open another. This works even if you app crashes.
Yes, it makes it impossible to open two instances at the same time.
However it's very important to be aware of the bugs. With some firewalls, it's impossible to open even one instance - your application crashes at startup! See this excellent article by Bill McCarthy for more details, and a technique for restricting your application to one instance. His technique for communicating the command-line argument from a second instance back to the first instance uses pipes in .NET 3.5.
Dim _process() As Process
_process = Process.GetProcessesByName(Process.GetCurrentProcess().ProcessName)
If _process.Length > 1 Then
MsgBox("El programa ya está ejecutandose.", vbInformation)
End
End If
I found a great article for this topic: Single Instance Application in VB.NET.
Example usage:
Module ModMain
Private m_Handler As New SingleInstanceHandler()
' You should download codes for SingleInstaceHandler() class from:
' http://www.codeproject.com/Articles/3865/Single-Instance-Application-in-VB-NET
Private m_MainForm As Form
Public Sub Main(ByVal args() As String)
AddHandler m_Handler.StartUpEvent, AddressOf StartUp ' Add the StartUp callback
m_Handler.Run(args)
End Sub
Public Sub StartUp(ByVal sender As Object, ByVal event_args As StartUpEventArgs)
If event_args.NewInstance Then ' This is the first instance, create the main form and addd the child forms
m_MainForm = New Form()
Application.Run(m_MainForm)
Else ' This is coming from another instance
' Your codes and actions for next instances...
End If
End Sub
End Module
Yes you're correct in that it will only allow one instance of your application to be open at a time.
There is even a easier method:
Use the following code...
Imports System.IO
On the main form load event do the following:
If File.Exist(Application.StartupPath & "\abc.txt") Then
'You can change the extension of the file to what ever you desire ex: dll, xyz etc.
MsgBox("Only one Instance of the application is allowed!!!")
Environment.Exit(0)
Else
File.Create(Application.StartupPath & "\abc.txt", 10, Fileoptions.DeleteonClose)
Endif
This will take care of single instances as well as thin clients, and the file cannot be deleted while the application is running. and on closing the application or if the application crashes the file will delete itself.