I have an application that I need to close after it is inactive or not used. I have written the below code and am getting
System.InvalidOperationException in windowsBase.dll
Do you have any idea how I can get this done? I need the application not to "freeze" using some of the threading timers.
Private Sub MainWindow_Loaded(sender As Object, e As RoutedEventArgs) Handles Me.Loaded
Dim aTimer As System.Timers.Timer
aTimer = New System.Timers.Timer()
aTimer.Interval = 9000
' Hook up the Elapsed event for the timer.
AddHandler aTimer.Elapsed, AddressOf OnTimedEvent
' Start the timer
aTimer.Enabled = True
End Sub
Private Sub OnTimedEvent(source As Object, e As System.Timers.ElapsedEventArgs)
Close()
End Sub
Try :
Dim app as Application
Private Sub OnTimedEvent(source As Object, e As System.Timers.ElapsedEventArgs)
app.Exit()
End Sub
That seems to have worked for me.
Here is my full code on a blank form I made to test your issue. I get the smae exception you get trying to use Me.Close() but my Application.Exit() and app.Exit() work without a problem.
Public Class Form1
Dim app As Application
Private Sub MainWindow_Loaded(sender As Object, e As EventArgs) Handles Me.Load
Dim aTimer As System.Timers.Timer
aTimer = New System.Timers.Timer()
aTimer.Interval = 5000
' Hook up the Elapsed event for the timer.
AddHandler aTimer.Elapsed, AddressOf OnTimedEvent
' Start the timer
aTimer.Enabled = True
End Sub
Private Sub OnTimedEvent(source As Object, e As System.Timers.ElapsedEventArgs)
'Environment.Exit(0) - closes without a problem
'Application.Exit() - closes without a problem
'closes without a problem.
app.Exit()
'Me.Close() - System.InvalidOperationException
End Sub
End Class
Related
I call my page every 20 seconds but when i call my page i see a flash. Is it possible to avoid the flickering when the page load?
Private Sub WebBrowser1_load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
WebBrowser1.Navigate(New Uri("http://metalrockpopradio.caramania.com/tuneefy4.php"))
Dim timer As New Timer()
timer.Interval = 20000
AddHandler timer.Tick, AddressOf WebBrowser1.Refresh
timer.Start()
You can do something like this:
Create a Form (here called Form1)
add a PictureBox (here, called PictureBox1) to it
set the PictureBox size to what you want and set its SizeMode = Zoom
paste the following code inside the Form's code partial file (F7 on the Form)
Imports System.Net
Imports System.Windows.Forms
Public Class Form1
Dim timer As System.Windows.Forms.Timer
Private client As WebClient = New WebClient()
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
RefreshImage(Nothing, Nothing)
timer = New System.Windows.Forms.Timer()
AddHandler timer.Tick, AddressOf Me.RefreshImage
timer.Interval = 5000
timer.Start()
End Sub
Protected Sub RefreshImage(sender As Object, e As EventArgs)
Dim HttpResource As String = client.DownloadString("http://metalrockpopradio.caramania.com/tuneefy4.php")
Dim ParseStart As Integer = HttpResource.IndexOf("=") + 2
HttpResource = HttpResource.Substring(ParseStart, HttpResource.LastIndexOf(ChrW(34)) - ParseStart)
If PictureBox1.Image IsNot Nothing Then PictureBox1.Image.Dispose()
PictureBox1.Load(HttpResource)
End Sub
Private Sub Form1_FormClosed(sender As Object, e As FormClosedEventArgs) Handles MyBase.FormClosed
client.Dispose()
timer.Dispose()
End Sub
End Class
Have two of them. When the new reload is done, show the new control and hide the old.
Alternatively, use AJAX or similar on your page to reload content.
I create timers within a class
Dim timer As New Timer
timer.Enabled = True
timer.Interval = 1000
timer.Tag = "TimeslipTimer_" & timeslip.id
AddHandler timer.Tick, AddressOf GlobalTimerTick
timer.Start()
The problem i have is how can I delete those if I needed?
At the moment I was looking to add timers to a list, similar to below, but i didnt work out
dim timers as new list(of Timer)
For Each c As Timer In Timers
c.Dispose()
Timers.Remove(c)
Next
When removing from a list the list must be accessed in reverse order. Also remember to remove the handler.
Public Class Form1
Private WithEvents timer As Timer
Private timers As New List(Of Timer)
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
timer = New Timer
timers.Add(timer)
timer.Enabled = True
timer.Interval = 1000
'timer.Tag = "TimeslipTimer_" & timeslip.id
AddHandler timer.Tick, AddressOf GlobalTimerTick
timer.Start()
End Sub
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
For x As Integer = timers.Count - 1 To 0 Step -1
Dim t As Timer = timers(x)
RemoveHandler t.Tick, AddressOf GlobalTimerTick
t.Stop()
t.Dispose()
timers.RemoveAt(x)
Next
End Sub
Private Sub GlobalTimerTick(sender As Object, e As EventArgs)
Debug.WriteLine("TICK")
End Sub
End Class
The application is doing a lot more than this, but I have narrowed down the issue with the example below.
When bgwDone.WaitOne() is commented out, the progress bar works fine, cancel button is effective, but execution continues before the background process is complete.
When bgwDone.WaitOne() is applied, the ProgressForm is visible but not enabled, so processing cannot be cancelled and progress bar does not refresh, and the most confusing part, Msgbox("1") does not execute. I only see Msgbox("2") after the background worker finishes. I am utterly perplexed.
Imports System.ComponentModel
Public Class Form1
Private WithEvents bgw As BackgroundWorker
Private Event bgwCancelled()
Private bgwDone As New System.Threading.AutoResetEvent(False)
'Allows ProgressForm to cancel execution
Public Sub bgwCancelAsync()
RaiseEvent bgwCancelled()
End Sub
Private Sub bgw_Cancelled_by_ProgressForm() Handles Me.bgwCancelled
bgw.CancelAsync()
End Sub
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Cursor = Cursors.WaitCursor
bgw = New BackgroundWorker
bgw.WorkerReportsProgress = True
bgw.WorkerSupportsCancellation = True
If bgw.IsBusy = False Then
ProgressForm.Show()
bgw.RunWorkerAsync(10)
End If
'********THIS LINE: bgwDone.WaitOne() MAKES A BIG DIFFERENCE*******
bgwDone.WaitOne()
MsgBox("1")
MsgBox("2")
Cursor = Cursors.Default
End Sub
'BackgroundWorker.RunWorkerAsync raises the DoWork event
Private Sub bgw_DoWork(sender As Object, e As DoWorkEventArgs) Handles bgw.DoWork
Dim numToDo As Integer = CInt(e.Argument)
For n As Integer = 1 To numToDo
If bgw.CancellationPending Then
Exit For
End If
System.Threading.Thread.Sleep(200)
bgw.ReportProgress(n * 10)
Next
bgwDone.Set()
End Sub
'ReportProgress raises the ProgressChanged event
Private Sub bgw_ProgressChanged(sender As Object, e As ProgressChangedEventArgs) Handles bgw.ProgressChanged
ProgressForm.UpdateProgress(e.ProgressPercentage)
End Sub
Private Sub bgw_RunWorkerCompleted(sender As Object,
e As RunWorkerCompletedEventArgs) Handles bgw.RunWorkerCompleted
ProgressForm.Close()
End Sub
And my form with the ProgressBar:
Public Class ProgressForm
Private Sub ButtonCancel_Click(sender As Object, e As EventArgs) Handles ButtonCancel.Click
Form1.bgwCancelAsync()
End Sub
Public Sub UpdateProgress(pct As Integer)
ProgressBar1.Value = pct
ProgressBar1.Refresh()
End Sub
End Class
I am not sure what you are trying to accomplish. But it almost seems like some of your code is trying to defeat the purpose of a BackGroundWorker:
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Cursor = Cursors.WaitCursor
bgw = New BackgroundWorker
...
If bgw.IsBusy = False Then
ProgressForm.Show()
bgw.RunWorkerAsync(10)
End If
bgwDone.WaitOne()
MsgBox("1")
MsgBox("2")
Cursor = Cursors.Default
End Sub
The purpose of a BackgroundWorker is to do some long running task on another thread and leave the UI responsive. I am not sure that a task that only "takes several seconds" qualifies as a long running task.
Given that, why use the WaitCursor while the BGW runs? The point to leaving the UI resposive is to allow the user to do other things in the meantime.
The test for bgw.IsBusy can never, ever be true - you just created it 3 lines earlier. Click the button again and you will create another BGW.
The rest of the code in the click looks like you want or expect the code to continue on the next line after the BGW completes. That's not how it works.
If the app cannot continue without those tasks being completed, disable anything that lets the user go elsewhere until the worker completes or:
Forego the worker and put the form in wait mode (Me.UseWaitCursor) until the stuff is loaded. This doesn't rule out a ProgressBar.
A dedicated Progress Form can make sense in cases where the app will use various workers at various times. A StatusBar can contain a ProgressBar and is much more subtle (and perhaps appropriate since it is a status element).
So, revised and using a form instance for the progress reporter:
MainForm
Private WithEvents bgw As BackgroundWorker
Private frmProg As ProgressForm
Public Sub New()
' This call is required by the designer.
InitializeComponent()
' Add any initialization after the InitializeComponent() call.
bgw = New BackgroundWorker
End Sub
Private Sub btnLoadAll_Click(sender As Object, e As EventArgs) Handles btnLoadAll.Click
bgw.WorkerReportsProgress = True
bgw.WorkerSupportsCancellation = True
If bgw.IsBusy = False Then
' create ProgressForm instance if needed
If frmProg Is Nothing Then frmProg = New ProgressForm
frmProg.Show()
bgw.RunWorkerAsync(78)
End If
btnLoadAll.Enabled = False
End Sub
Private Sub bgw_DoWork(sender As Object, e As DoWorkEventArgs) Handles bgw.DoWork
' multiple workers can use the same event
Dim thisWorker = DirectCast(sender, BackgroundWorker)
Dim count = Convert.ToInt32(e.Argument)
For n As Integer = 1 To count
If thisWorker.CancellationPending Then
Exit For
End If
' Fake work:
System.Threading.Thread.Sleep(50)
' dont assume the size of the job if
' there are multiple BGW or tasks
thisWorker.ReportProgress(Convert.ToInt32((n / count) * 100))
Next
End Sub
Private Sub bgw_ProgressChanged(sender As Object,
e As ProgressChangedEventArgs) Handles bgw.ProgressChanged
frmProg.UpdateProgress(e.ProgressPercentage)
End Sub
Private Sub bgw_RunWorkerCompleted(sender As Object,
e As RunWorkerCompletedEventArgs) Handles bgw.RunWorkerCompleted
If e.Error IsNot Nothing Then
'... ToDo
ElseIf e.Cancelled Then
'... ToDo
Else
frmProg.Close()
' avoid 'cannot access disposed object':
frmProg = Nothing
Me.btnNextStep.Enabled = True
btnLoadAll.Enabled = True
End If
End Sub
Rather than enabling a "Next" button, the app could automatically proceed. It depends on the app.
I want to delete file after 15 second of create that file.
I use this code but no success.
Private Sub Form1_Click(sender As Object, e As EventArgs) Handles Me.Click
Dim test = Application.StartupPath & "\" + tte4
Timer1.Enabled = True
If Timer1.Interval = 0 Then
My.Computer.FileSystem.DeleteFile(test)
End If
End Sub
You must handle the timed event in a handler for the Timer's Tick Event (or Elapsed if using System.Timers.Timer):
Private m_strTest As String = String.Empty
Private Sub Form1_Click(sender As Object, e As EventArgs) Handles Me.Click
m_strTest = Application.StartupPath & "\" + tte4
Timer1.Enabled = True
End Sub
If using System.Forms.Timer (most likely):
Private Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick
System.IO.File.Delete(m_strTest)
Timer1.Enabled = False
End Sub
If using System.Timers.Timer:
Private Sub Timer1_Elapsed(ByVal source As Object, ByVal e As ElapsedEventArgs) Handles Timer1_Elapsed
System.IO.File.Delete(m_strTest)
Timer1.Stop()
End Sub
If you added your Timer from the Toolbox, the above code will work (due to WithEvents). If you added it programatically, you'll also have to wire up the Event Handler and remove the Handles from your Timer1_Tick Method:
Private Sub Form1_Click(sender As Object, e As EventArgs) Handles Me.Click
m_strTest = Application.StartupPath & "\" + tte4
AddHandler Timer1.Tick, AddressOf Timer1_Tick
Timer1.Enabled = True
End Sub
Private Sub Timer1_Tick(sender As Object, e As EventArgs)
System.IO.File.Delete(m_strTest)
Timer1.Enabled = False
End Sub
You need define a method that the timer fires when the interval elapses.
' Timer set to fire every 15 seconds
Dim Timer1 As New Timer(15000)
' OnTimedEvent is the method that will fire after 15 seconds
AddHandler Timer1.Elapsed, AddressOf OnTimedEvent
' Start the Timer
Timer1.Start()
The OnTimedEvent is as followed:
Private Sub OnTimedEvent(source As Object, e As ElapsedEventArgs)
' Stop the timer from firing again
Timer1.Stop()
' Delete your file
End Sub
Reference
https://msdn.microsoft.com/en-us/library/k0wdddfy(v=vs.110).aspx?cs-save-lang=1&cs-lang=vb#code-snippet-1
You have the right idea in using a Timer to wait for the deletion, but your way of trying to use it is incorrect. A (System.Windows.Forms) Timer raises an event when it ticks, and you need to tie that event to the code you want to run.
Also, to combine parts of a path it is better to use IO.Path.Combine, and when doing file operations it is a good idea to "wrap" the relevant code in a Try..Catch construct and handle the exception if it happens.
So:
Option Infer On
Option Strict On
Imports System.IO
Public Class Form1
Dim tim1 As New System.Windows.Forms.Timer
Dim tte4 As String = "afile.txt"
Private Sub Timer1_Tick(sender As Object, e As EventArgs)
tim1.Enabled = False
Dim target = Path.Combine("C:\temp", tte4)
If File.Exists(target) Then
Try
File.Delete(target)
Catch ex As Exception
MessageBox.Show(String.Format("The file ""{0}"" could not be deleted because {1}", target, ex.Message))
End Try
Else
' the file does not exist - do something if required
End If
End Sub
Private Sub SetUpTimer()
tim1.Enabled = False
tim1.Interval = 1000 * 15
' here we tie the event to the code
AddHandler tim1.Tick, AddressOf Timer1_Tick
End Sub
Private Sub Form1_Click(sender As Object, e As EventArgs) Handles MyBase.Click
' this has the side-effect of trying to delete a file after an interval
tim1.Enabled = True
End Sub
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
SetUpTimer()
End Sub
End Class
You did not show code for creating the file - I assume you used a click on the form just to demonstrate the idea.
I could easily close form after few seconds; but when I want to close many forms one after another, same sequence as they were "created"; I could not figure it out:
The main form code is as below:
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim numberOfForms As Integer = 10
For open = 1 To numberOfForms
TestClosing()
Next
End Sub
The module code that I am trying to create then close forms after few seconds is as below:
Imports System.Timers
Module ClosingModule
Sub TestClosing()
Dim frmNew As New Form
frmNew.Show()
Dim tmr As New System.Timers.Timer()
tmr.Interval = 3000
tmr.Enabled = True
tmr.Start()
End Sub
End Module
I started a timer, but all the methods I tried to close the form is same sequence they were created; were not successful;
Help appreciated; and thanks in advance.
Add the Timer to the Forms you are creating, start it when the Form is created that way they will be closed in the same order that they were created. I also added an incremental delay to that the order of closing is more evident.
Form1
Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
Dim numberOfForms As Integer = 10
For open = 1 To numberOfForms
Dim frmNew As New Form2
frmNew.Text = open.ToString
frmNew.Show()
Next
End Sub
Form2
Public Class Form2
Dim myTimer As New Timer()
Private Sub myTimer_Tick(sender As System.Object, e As System.EventArgs)
myTimer.Stop()
Me.Close()
End Sub
Private Sub Form2_Shown(sender As Object, e As System.EventArgs) Handles Me.Shown
myTimer.Interval = 1000 * CInt(Me.Text)
AddHandler myTimer.Tick, AddressOf myTimer_Tick
myTimer.Start()
End Sub
End Class
Added code in module to do the same thing:
Imports System.Timers
Module ClosingModule
Sub TestClosing(multiplier As Integer)
Dim frmNew As New Form
frmNew.Show()
Dim tmr As New System.Timers.Timer()
AddHandler tmr.Elapsed, AddressOf Timer_Elapsed 'Add Handler to New Timer
tmr.SynchronizingObject = frmNew 'Synchronize Timer to newly created form
tmr.Interval = 1000 * multiplier
tmr.Enabled = True
tmr.Start()
End Sub
Public Sub Timer_Elapsed(sender As Object, e As ElapsedEventArgs)
Dim tmr As System.Timers.Timer = DirectCast(sender, System.Timers.Timer)
tmr.Stop() 'Stop Timer
DirectCast(tmr.SynchronizingObject, Form).Close() 'Get Form Timer was synchronized with and close it
tmr.SynchronizingObject = Nothing 'Remove Form reference from timer
RemoveHandler tmr.Elapsed, AddressOf Timer_Elapsed 'Remove Handler from Timer
End Sub