Vb.Net Wait for webbrowser finish navigate - vb.net

How can i wait till webbrowser loaded the page?
i tried:
webbrowser1.navigate(url)
msgbox("done")

This is the approach I used when I was having the same problem. By adding a handler you dont have to use a timer to unnecessary processing instead the event will fire as soon as the document has loaded. Dont be fooled by the name documentcompleted, it's actually waiting for the webpage to load.
AddHandler (webbrowser1.DocumentCompleted), AddressOf WebpageLoaded
webbrowser1.Navigate(url)
Public Sub WebpageLoaded(sender As System.Object, e As System.Windows.Forms.WebBrowserDocumentCompletedEventArgs)
MessageBox.Show("Done")
End Sub
Im not saying this is the best way to go but it worked well for me :)

Do While wb.ReadyState <> WebBrowserReadyState.Complete
Application.DoEvents()
Loop

I inherit a new class from WebBrowser control:
Public Class WebBrowserSyncFW
Inherits WebBrowser
Public Async Function NavigateSync(ByVal urlString As String, Optional ByVal timeoutmillisec As Integer = 30000) As Task(Of Boolean)
Dim IsLoaded As Boolean = False
Me.ScriptErrorsSuppressed = True
Me.Navigate(urlString)
AddHandler Me.DocumentCompleted, Sub(sender As Object, e As WebBrowserDocumentCompletedEventArgs)
IsLoaded = True
End Sub
For i = 1 To timeoutmillisec / 100
Await Task.Delay(100).ConfigureAwait(False)
If IsLoaded = True Then Return True
Next
Return False
End Function
End Class
Usage:
If Await WebBrowserSyncFW1.NavigateSync("http://www.youtube.com") Then
MsgBox("Page is loaded!", MsgBoxStyle.Information)
Else
MsgBox("Timeout!", MsgBoxStyle.Exclamation)
End If

Related

Bug on login form while trying to close the app vb.net

So currently I am using a code which provides me the possibility to manager whenever or not the application will logout or keep on track. Basically if the user is not using the program for quite some time it will move to the Login form and of course if the user wants to login back he had to type again.
I got a class where I am able to produce more or less that code:
Public Class TimerWatcher
Private _timer As System.Threading.Timer
Private _enabled As Boolean
Private _lastEvent As DateTime
Public Sub New()
_timer = New System.Threading.Timer(AddressOf watch)
_enabled = False
Timeout = 0
End Sub
Public Event Idle(sender As Form)
Public Property Timeout As Long
Public Property Enabled As Boolean
Get
Return _enabled
End Get
Set(value As Boolean)
If value Then
_lastEvent = DateTime.Now
_timer.Change(0, 1000)
Else
_timer.Change(System.Threading.Timeout.Infinite, System.Threading.Timeout.Infinite)
End If
End Set
End Property
Private Sub watch()
If DateTime.Now.Subtract(_lastEvent).TotalMilliseconds > Timeout Then
Enabled = False
' "End" is quite blunt. You may want to raise an event
' so the form can terminate the application gracefully.
RaiseEvent Idle(Login)
End If
End Sub
Public Sub Refresh()
_lastEvent = DateTime.Now
End Sub
End Class
And then on my main form I got this:
Private Sub MainForm_Load(sender As Object, e As EventArgs) Handles MyBase.Load
watcher.Timeout = 5000
watcher.Enabled = True
End Sub
Private Sub PaginaInicial_MouseMove(sender As Object, e As MouseEventArgs) Handles Me.MouseMove
watcher.Refresh()
End Sub
Private Sub watcher_idle(sender As Form) Handles watcher.Idle
Dim logIN = New Login
If MsgBox("The application will close, are you sure you want to do it?", MsgBoxStyle.YesNo) = MsgBoxResult.Yes Then
logIN.Show()
Else
End If
End Sub
But, because some bug I am not able to return the Login form...And this is what happen to the form after I click yes on the MessageBox. The login form crash or something
Do you have any idea how I can solve this bug?

Showing WinSCP .NET assembly transfer progress on WinForm's progress bar

Have some main form on which I am calling file downloading from FTP. When this operation is raised i want to see new form as ShowDialog and progress bar on it to be shown meantime, then show the progress and close new form and back to main form. My code is working however, when it will process is started my main form freezes and after while new form is appearing and then closing. What I would like to correct is to show this new form to be showed straightaway after process is executed. Can you take a look and tell me whats wrong?
This is out of my main form the download process called:
Dim pro As New FrmProgressBarWinscp(WinScp, myremotePicturePath, ladujZdjeciaPath, True)
FrmProgressBarWinscp is as follows:
Public Class FrmProgressBarWinscp
Property _winScp As WinScpOperation
Property _remotePicture As String
Property _ladujZdjecia As String
Property _removesource As String
Public Sub New()
InitializeComponent()
End Sub
Sub New(winscp As WinScpOperation, remotePicture As String, ladujzdjecia As String, removesource As Boolean)
' This call is required by the designer.
InitializeComponent()
' Add any initialization after the InitializeComponent() call.
_winScp = winscp
_remotePicture = remotePicture
_ladujZdjecia = ladujzdjecia
_removesource = removesource
ShowDialog()
End Sub
Sub Run()
Try
Cursor = Cursors.WaitCursor
_winScp.GetFile(_remotePicture, _ladujZdjecia, _removesource)
ProgressBar1.Minimum = 0
ProgressBar1.Maximum = 1
ProgressBar1.Value = 0
Do
ProgressBar1.Value = WinScpOperation._lastProgress
ProgressBar1.Refresh()
Loop Until ProgressBar1.Value = 1
Cursor = Cursors.Default
'Close()
Catch ex As Exception
Finally
If _winScp IsNot Nothing Then
_winScp.SessionDispose()
End If
System.Threading.Thread.Sleep(10000)
Close()
End Try
End Sub
Private Sub FrmProgressBarWinscp_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Run()
End Sub
End Class
Winscp my own class and used methods:
...
Function GetFile(source As String, destination As String, Optional removeSource As Boolean = False)
Dim result As Boolean = True
Try
session.GetFiles(source, destination, removeSource).Check()
Catch ex As Exception
result = False
End Try
Return result
End Function
Private Shared Sub SessionFileTransferProgress(sender As Object, e As FileTransferProgressEventArgs)
'Print transfer progress
_lastProgress = e.FileProgress
End Sub
Public Shared _lastProgress As Integer
...
Further discussion nr 3:
Main form:
Dim tsk As Task(Of Boolean) = Task.Factory.StartNew(Of Boolean)(Function()
Return WinScp.GetFile(myremotePicturePath, ladujZdjeciaPath, True)
End Function)
Dim forma As New FrmProgressBar
forma.ShowDialog()
Progress bar form:
Public Class FrmProgressBar
Public Sub New()
InitializeComponent()
End Sub
Sub Run()
Try
Do
ProgressBar1.Value = WinScpOperation._lastProgress
ProgressBar1.Refresh()
Loop Until ProgressBar1.Value = 1
Cursor = Cursors.Default
Catch ex As Exception
Finally
MsgBox("before sleep")
System.Threading.Thread.Sleep(10000)
MsgBox("after sleep sleep")
Close()
End Try
End Sub
Private Sub FrmProgressBarWinscp_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Run()
End Sub
End Class
Point nr. 4:
Dim tsk As Task(Of Boolean) = Task.Factory.StartNew(Of Boolean)(Function()
Return WinScp.GetFile(myremotePicturePath, ladujZdjeciaPath, True)
End Function)
Dim pic As New Waiting
pic.ShowDialog()
Task.WaitAll(tsk)
pic.Close()
Point 5:
Dim pic As New Waiting
pic.ShowDialog()
Dim tsk As Task = Task.Factory.StartNew(Sub() WinScp.GetFile(myremotePicturePath, ladujZdjeciaPath, pic, True))
Task.WaitAll(tsk)
'pic.Close()
In some other class (maybe didn't mentioned before this method is placed in diffrent class - my custom one)
Public Function GetFile(source As String, destination As String, formclose As InvokeCloseForm, Optional removeSource As Boolean = False) As Boolean
Dim result As Boolean = True
Try
session.GetFiles(source, destination, removeSource).Check()
Catch ex As Exception
result = False
End Try
formclose.RUn()
Return result
End Function
Interface:
Public Interface InvokeCloseForm
Sub RUn()
End Interface
Waiting form :
Public Class Waiting
Implements InvokeCloseForm
Public Sub RUn() Implements InvokeCloseForm.RUn
Me.Close()
End Sub
End Class
The Session.GetFiles method in blocking.
It means it returns only after the transfer finishes.
The solution is to:
Run the WinSCP transfer (the Session.GetFiles) in a separate thread, not to block the GUI thread.
For that see WinForm Application UI Hangs during Long-Running Operation
Handle the Session.FileTransferProgress event.
Though note that the event handler will be called on the background thread, so you cannot update the progress bar directly from the handler. You have to use the Control.Invoke to make sure the progress bar is updated on the GUI thread.
For that see How do I update the GUI from another thread?
A trivial implementation is below.
For a more version of the code, see WinSCP article Displaying FTP/SFTP transfer progress on WinForms ProgressBar.
Public Class ProgressDialog1
Private Sub ProgressDialog1_Load(
sender As Object, e As EventArgs) Handles MyBase.Load
' Run download on a separate thread
ThreadPool.QueueUserWorkItem(New WaitCallback(AddressOf Download))
End Sub
Private Sub Download(stateInfo As Object)
' Setup session options
Dim mySessionOptions As New SessionOptions
With mySessionOptions
...
End With
Using mySession As Session = New Session
AddHandler mySession.FileTransferProgress,
AddressOf SessionFileTransferProgress
' Connect
mySession.Open(mySessionOptions)
mySession.GetFiles(<Source>, <Destination>).Check()
End Using
' Close form (invoked on GUI thread)
Invoke(New Action(Sub() Close()))
End Sub
Private Sub SessionFileTransferProgress(
sender As Object, e As FileTransferProgressEventArgs)
' Update progress bar (on GUI thread)
ProgressBar1.Invoke(
New Action(Of Double)(AddressOf UpdateProgress), e.OverallProgress)
End Sub
Private Sub UpdateProgress(progress As Double)
ProgressBar1.Value = progress * 100
End Sub
End Class
You may want to disable the progress form (or its parts) during the operation, if you want to prevent the user from doing some operations.
Use the .Enabled property of the form or control(s).
Easier, but hacky and generally not recommendable solution, is to call the Application.DoEvents method from your existing SessionFileTransferProgress handler.
And of course, you have to update the progress bar from the the SessionFileTransferProgress as well.
Private Shared Sub SessionFileTransferProgress(
sender As Object, e As FileTransferProgressEventArgs)
'Print transfer progress
ProgressBar1.Value = e.FileProgress
Application.DoEvents
End Sub
And the progress bar's .Minimum and .Maximum must be set before the Session.GetFiles.
But do not do that! That's a wrong approach.
And still, you need to disable the forms/controls the same way as in the correct solution above.

VB.NET : Thread is running or terminated; it cannot restart

I've encounter this error when using multi-threading. I'm new with it, in my windows application this code works. But I transfer it to windows services I've received "Thread is running or terminated; it cannot restart." I'm using System.Timers.Timer instead of System.Windows.Forms.Timer as recommended when creating it in Windows services. This windows services will export some XML file from database, so I need a timer. So time to time, it will check if there's a new products or customer in the database which reads the function below. By default, I've hard coded the time to 1min for testing. Also, I've created a boolean variable if the function is not finish yet. It will not override.
Here's my code :
Dim oIsproc_BP As Boolean
Dim oIsproc_ItemMaster1 As Boolean
Dim thrd As Thread
Protected Overrides Sub onstart(ByVal args() As String)
tmr.Interval = 1000
AddHandler tmr.Elapsed, AddressOf tmr_Elapsed
tmr.Start()
End Sub
Private Sub tmr_Elapsed(sender As Object, e As Timers.ElapsedEventArgs) Handles tmr.Elapsed
oIsproc_BP = False
oIsproc_ItemMaster1 = False
tSecItemMaster.Interval = 60000'oInterval(0)
AddHandler tSecItemMaster.Elapsed, AddressOf tSecItemMaster_Elapsed
tSecItemMaster.Start()
tSecCustomer.Interval = 60000'oInterval(2)
AddHandler tSecCustomer.Elapsed, AddressOf tSecCustomer_Elapsed
tSecCustomer.Start()
tmr.Stop()
End Sub
Private Sub tSecItemMaster_Elapsed(sender As Object, e As Timers.ElapsedEventArgs) Handles tSecItemMaster.Elapsed
If Not oIsproc_ItemMaster1 Then
oIsproc_ItemMaster1 = True
thrd = New Thread(DirectCast(Function() oItemMaster(), ThreadStart))
thrd.Start()
End If
Return
End Sub
Private Sub tSecCustomer_Elapsed(sender As Object, e As Timers.ElapsedEventArgs) Handles tSecCustomer.Elapsed
If Not oIsproc_BP Then
oIsproc_BP = True
thrd = New Thread(DirectCast(Sub() oBPartners(, "C"), ThreadStart))
thrd.Start()
End If
Return
End Sub
And for my function :
Private Function oItemMaster(Optional ByVal FirstLoad As Boolean = False, Optional oType As Integer = 1)
''My code here
oIsproc_ItemMaster1 = False
End Function
Private Sub oBPartners(Optional ByVal FirstLoad As Boolean = False, Optional CardType As String = "C")
''My code here
oIsproc_BP = False
End Function
You have a race - you're using a single variable (thrd) to hold one of two instances of a Thread that you might create. Consider both timers firing at the same time, and the threads that service the timers being interleaved as follows:
Timer 1 (tSecItemMaster_Elapsed) Timer 2 (tSecCustomer_Elapsed)
If Not oIsproc_ItemMaster1 Then
oIsproc_ItemMaster1 = True
If Not oIsproc_BP Then
oIsproc_BP = True
thrd = New Thread(...)
thrd = New Thread(...)
thrd.Start()
End If
Return
thrd.Start()
End If
Return
And that's why you get the error message - both timers are trying to start the single Thread object that was created inside tSecItemMaster_Elapsed, and the Thread created inside of tSecCustomer_Elapsed is never started. Other inter-leavings will introduce similar issues.
A quick fix would be to create a separate field for storing each thread. I think you may still have a couple of race conditions but they're not leaping out at me at the moment.

Confusing System.NullReferenceException error on a defined variable - VB

Alright so I am new here so I apologize in advance if I post incorrectly or am a little vague. My problem is that I run into a NullReferenceException when I try to run my code but while debugging and hovering my mouse over the problematic variable, I do indeed see the value of the variable.
Here is the VB code that I am working with:
Private Sub Login_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles login.Click
status.Text = "Connecting...."
WebBrowser2.Navigate("http://*****.com/?op=login")
WebBrowser2.Document.GetElementById("loginUsername").InnerText = username.Text
WebBrowser2.Document.GetElementById("loginPassword").InnerText = password.Text
WebBrowser2.Document.GetElementById("loginSubmit").InvokeMember("click")
End Sub
Here is the snapshot of what is going on:
------------ EDIT : SOLUTION -------------------
WebBrowser2.Url = New Uri("http://*****.com/?op=login")
WaitForPageLoad() ' <---------- ADDED NEW FUNCTION TO WAIT FOR PAGE LOAD
WebBrowser2.Document.GetElementById("loginUsername").InnerText = username.Text
WebBrowser2.Document.GetElementById("loginPassword").InnerText = password.Text
WebBrowser2.Document.GetElementById("loginSubmit").InvokeMember("click")
status.Text = "Completed"
So I created a new function (credits go to BGM in How to wait until WebBrowser is completely loaded in VB.NET?) called WaitForPageLoad() which essentially loops through a check for the page to be ready and then once it is, is kills the handler so the login is successful and the page does not loop. Here is the WaitForPageLoad():
Private Property pageready As Boolean = False
Private Sub WaitForPageLoad()
AddHandler WebBrowser2.DocumentCompleted, New WebBrowserDocumentCompletedEventHandler(AddressOf PageWaiter)
While Not pageready
Application.DoEvents()
End While
pageready = False
End Sub
Private Sub PageWaiter(ByVal sender As Object, ByVal e As WebBrowserDocumentCompletedEventArgs)
If WebBrowser2.ReadyState = WebBrowserReadyState.Complete Then
pageready = True
RemoveHandler WebBrowser2.DocumentCompleted, New WebBrowserDocumentCompletedEventHandler(AddressOf PageWaiter)
End If
End Sub
WebBrowser2.Navigate takes some time to load the document, but is asynchronous. That means that the next code gets executed before the document finishes loading.
Consequently, in the next line, GetElementById cannot yet find the target element and returns Nothing. To prevent this, you cannot execute code after calling Navigate – instead, you need to create an event handler for the event that is fired once the document finished loading, and execute the code there. – This is the DocumentCompleted event.
On that line in particular...
Document could be null
The result of GetElementById("loginUsername") could be null.
Why do you think that username is null?
I bet that WebBrowser2.Document.GetElementById("loginUsername") returns null.
The other possibility is Document to be null.

vb.net how do I make an application that only has a notifyicon and no windows form?

I want to make an application that only has a notifyicon and doesn't have any visible window form when it starts up. I see some example sort of like what I want to do for c#, but I don't see how to do this in vb.net project.
A form is not strictly necessary. You can instantiate a NotifyIcon and use that without creating a form:
Public Class AppContext
Inherits ApplicationContext
Private notifyIcon As NotifyIcon
Private appActive As Boolean
Public Sub New()
AddHandler Application.ApplicationExit, AddressOf OnApplicationExit
notifyIcon = New NotifyIcon()
notifyIcon.Icon = My.Resources.ActiveIcon
notifyIcon.Text = "The app is active."
AddHandler notifyIcon.MouseClick, AddressOf OnIconMouseClick
appActive = True
notifyIcon.Visible = True
End Sub
Private Sub OnApplicationExit(ByVal sender As Object, ByVal e As EventArgs)
If notifyIcon IsNot Nothing Then
notifyIcon.Dispose()
End If
End Sub
Private Sub OnIconMouseClick(ByVal sender As Object, ByVal e As MouseEventArgs)
If e.Button = MouseButtons.Left Then
appActive = Not appActive
notifyIcon.Icon = If(appActive, My.Resources.ActiveIcon, My.Resources.InactiveIcon)
notifyIcon.Text = If(appActive, "The app is active.", "The app is not active.")
Else
If MsgBox("Do you want to Exit?", MsgBoxStyle.YesNo) = MsgBoxResult.Yes Then
notifyIcon.Visible = False
ExitThread()
End If
End If
End Sub
End Class
And then start your app from a Sub Main:
Public Module EntryPoint
Public Sub Main()
Dim ctx As New AppContext()
Application.Run(ctx)
End Sub
End Module
Just put the form transparent and resize it to 1x1..
And add a notifyicon..
And on the Form Load Event do this:
NotifyIcon.Visible = True
Then make what ever you want..
You can create a context menu strip (A Menu when you right click on it )
PS: If you do it, You need to go on the NotifyIcon properties and set the Context Menu Strip to that you created..
Hope it helped you..