Random delay in seconds from numericupdown in VB.Net - vb.net

I have a desktop winforms app code:
Sub Delay(ByVal dblSecs As Double)
Const OneSec As Double = 1.0# / (1440.0# * 60.0#)
Dim dblWaitTil As Date
Now.AddSeconds(OneSec)
dblWaitTil = Now.AddSeconds(OneSec).AddSeconds(dblSecs)
Do Until Now > dblWaitTil
Application.DoEvents()
Loop
End Sub
Private Sub btnStart_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnStart.Click
Webbrowser1.Navigate(TextBox1.Text)
Delay(Val(DelayText.Text))
end sub
What I need is to set max. delay, same from textbox by entering seconds.
I need this to be random delay number so Im stacking here, thanks for correcting my code.
Also If its possible to make it in NumericUpDown, as i found some topics which says textbox text property is different as NumericUpDown but i like it more.

You could use an inbetween class which does most of the work for you
This class would take the WebBrowser, attach to some events of it, and would refresh periodically (depending on MinimumWait / MaximumWait)
As it is using threading, it also checks if the usercontrol needs to be invoked to Refresh it and when yes, invokes the custom refresh delegate
Public Class Refresher
Protected Delegate Sub RefreshNavigationDelegate(browser As WebBrowser)
Protected Sub RefreshNavigation(browser As WebBrowser)
If browser.InvokeRequired Then
browser.Invoke(New RefreshNavigationDelegate(AddressOf RefreshNavigation), browser)
Return
End If
browser.Refresh(WebBrowserRefreshOption.Completely)
End Sub
Private _isBusy As Boolean = False
Public Property IsBusy As Boolean
Get
Return _isBusy
End Get
Protected Set(value As Boolean)
If _isBusy = value Then
Return
End If
_isBusy = value
End Set
End Property
Public Property MinimumWait As Integer = 2000
Public Property MaximumWait As Integer = 10000
Private refreshThread As Thread = Nothing
Private _browser As WebBrowser
Public Property Browser As WebBrowser
Get
Return _browser
End Get
Set(value As WebBrowser)
If Object.Equals(_browser, value) Then
Return
End If
StopRefresh()
If _browser IsNot Nothing Then
RemoveHandler Browser.DocumentCompleted, AddressOf DocumentComplete
RemoveHandler Browser.Navigating, AddressOf Navigating
End If
_browser = value
If _browser IsNot Nothing Then
AddHandler Browser.DocumentCompleted, AddressOf DocumentComplete
AddHandler Browser.Navigating, AddressOf Navigating
AddHandler Browser.ProgressChanged, AddressOf ProgressChanged
End If
StartRefresh()
End Set
End Property
Protected Sub ProgressChanged(sender As Object, e As WebBrowserProgressChangedEventArgs)
IsBusy = e.CurrentProgress > 0 AndAlso e.CurrentProgress < e.MaximumProgress
End Sub
Protected Sub DocumentComplete(sender As Object, e As WebBrowserDocumentCompletedEventArgs)
IsBusy = False
End Sub
Protected Sub Navigating(sender As Object, e As WebBrowserNavigatingEventArgs)
IsBusy = True
End Sub
Public Sub StartRefresh()
If refreshThread IsNot Nothing Then
Return
End If
refreshThread = New Thread(AddressOf DoRandomRefreshes)
refreshThread.Start()
End Sub
Public Sub StopRefresh()
If refreshThread Is Nothing Then
Return
End If
refreshThread.Abort()
refreshThread = Nothing
End Sub
Protected Overridable Sub DoRandomRefreshes()
Dim randomGenerator As New Random()
While Not refreshThread.ThreadState = ThreadState.AbortRequested
Dim newTimeout As Integer = MinimumWait + randomGenerator.Next(MaximumWait - MinimumWait)
Thread.Sleep(newTimeout)
If Not IsBusy Then
RefreshNavigation(Browser)
End If
End While
End Sub
Public Sub New()
End Sub
End Class
You could then use it in your form as such:
Public Class Form1
Dim myRefresher As Refresher = New Refresher()
Private Sub tsbGo_Click(sender As Object, e As EventArgs) Handles tsbGo.Click
WebBrowser1.Navigate(txtUrl.Text)
End Sub
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
myRefresher.Browser = WebBrowser1
End Sub
Private Sub txtMin_TextChanged(sender As Object, e As EventArgs) Handles txtMin.TextChanged
Dim int As Integer = 0
If Integer.TryParse(txtMin.Text, int) Then
myRefresher.MinimumWait = int
End If
End Sub
Private Sub txtMax_TextChanged(sender As Object, e As EventArgs) Handles txtMax.TextChanged
Dim int As Integer = 0
If Integer.TryParse(txtMax.Text, int) Then
myRefresher.MaximumWait = int
End If
End Sub
End Class

Related

Adding an event handler to custom control

I have created a custom control (Check Box) with a custom EventHandler
Public Event CheckedChanged As EventHandler
Private Sub setCheckStateUI(sender As Object, e As EventArgs)
...
RaiseEvent CheckedChanged(sender, e)
End Sub
It works fine without any errors if I added this control directly to a form. But when I add this to another custom control (a page of settings window) and that second custom control add to a form (settings window) the 'settings window' freeze and visual studio auto restart.
If I removed this event handler in the code the problem is gone.
What can be the problem here?
Thanks in advance
Update: (Complete code of the Custom Control)
Public Class cusCheckBox
Private mystring As String
Private CheckButtonState As Integer = 0
Public Event CheckedChanged As EventHandler
Public Sub New()
' This call is required by the designer.
InitializeComponent()
' Add any initialization after the InitializeComponent() call.
mystring = Me.Name
setSizes()
End Sub
Public Property CheckState() As Integer
Get
CheckState = CheckButtonState
End Get
Set(ByVal value As Integer)
CheckButtonState = value
chkButton.CheckState = CheckButtonState
End Set
End Property
Public Property LabelText() As String
Get
LabelText = mystring
End Get
Set(ByVal value As String)
mystring = value
lblText.Text = mystring
setSizes()
End Set
End Property
Public Overrides Property Font As Font
Get
Return lblText.Font
End Get
Set(value As Font)
lblText.Font = value
End Set
End Property
Private Sub chkButton_CheckedChanged(sender As Object, e As EventArgs) Handles chkButton.CheckedChanged
If chkButton.CheckState = 1 Then
chkButton.Image = Global.MYLogs.My.Resources.Resources.btnToggleOn
CheckButtonState = 1
Else
chkButton.Image = Global.MYLogs.My.Resources.Resources.btnToggleOff
CheckButtonState = 0
End If
End Sub
Private Sub lblText_Click(sender As Object, e As EventArgs) Handles lblText.Click
setCheckStateUI(sender, e)
End Sub
Private Sub cusCheckBox_MouseClick(sender As Object, e As MouseEventArgs) Handles Me.MouseClick
setCheckStateUI(sender, e)
End Sub
Private Sub cusCheckBox_Load(sender As Object, e As EventArgs) Handles MyBase.Load
setCheckStateUI(sender, e)
setSizes()
End Sub
Private Sub cusCheckBox_Resize(sender As Object, e As EventArgs) Handles Me.Resize
setSizes()
End Sub
Private Sub setSizes()
Me.Size = New Size(chkButton.Width + lblText.Width + 4, chkButton.Height)
End Sub
Private Sub setCheckStateUI(sender As Object, e As EventArgs)
If chkButton.CheckState = 0 Then
chkButton.Image = Global.MYLogs.My.Resources.Resources.btnToggleOn
chkButton.CheckState = 1
CheckButtonState = 1
Else
chkButton.Image = Global.MYLogs.My.Resources.Resources.btnToggleOff
chkButton.CheckState = 0
CheckButtonState = 0
End If
RaiseEvent CheckedChanged(Me, EventArgs.Empty)
chkButton.Select()
End Sub
End Class

how to safe call a control from another thread using Timers.Timer

I read various posts, and made a practice project, but it does not works.
The form have a button and a text box with a default text 'Updated 0 times'. On button click starts the timer and each time update the text with the number of times the text was updated.
The exception of cross thread calls is not thrown, but when calling the text box, its .Text = "", the text is updated but not the text box on the form. And InvokeRequired is always false.
Public Class Form1
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
'Here the textBox.Text = "Updated 0 times."
Dim checking_text As String = Me.TextBox1.Text
TimerTest.StartTimer()
End Sub
Delegate Sub UpdateTextInvoke(ByVal new_text As String)
Public Sub UpdateText(ByVal new_text As String)
'Here the textBox.Text = ""
Dim txtB As TextBox = Me.TextBox1
'InvokeRequired always = False.
If txtB.InvokeRequired Then
Dim invk As New UpdateTextInvoke(AddressOf UpdateText)
txtB.Invoke(invk, New Object() {new_text})
Else
'The value of this text box is updated, but the text on the form TextBox1 never changes
txtB.Text = new_text
End If
End Sub
End Class
Public Class TimerTest
Private Shared tmr As New System.Timers.Timer
Private Shared counter As Integer
Public Shared Sub StartTimer()
tmr.Interval = 5000
AddHandler tmr.Elapsed, AddressOf UdpateText
tmr.Enabled = True
End Sub
Public Shared Sub UdpateText(ByVal sender As Object, ByVal e As System.EventArgs)
counter += 1
Form1.UpdateText(String.Format("Updated {0} time(s).", counter))
End Sub
End Class
SOLVED
In the Class TimerTest added this code 'Private Shared myform As Form1 = Form1'
then changed 'Form1.UpdateText' To 'myform.UpdateText'
As indicated in the comments, you are using the default form instance feature of VB.Net. You could pass an instance of the form to the TimerTest class, and replace the reference to Form1 with the instance.
Public Class Form1
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim checking_text As String = Me.TextBox1.Text
TimerTest.StartTimer(Me)
End Sub
Public Sub UpdateText(new_text As String)
If TextBox1.InvokeRequired Then
Dim invk As New Action(Of String)(AddressOf UpdateText)
TextBox1.Invoke(invk, {new_text})
Else
TextBox1.Text = new_text
End If
End Sub
End Class
Public Class TimerTest
Private Shared tmr As New System.Timers.Timer()
Private Shared counter As Integer
Private Shared instance As Form1
Public Shared Sub StartTimer(formInstance As Form1)
instance = formInstance
tmr.Interval = 5000
AddHandler tmr.Elapsed, AddressOf UdpateText
tmr.Enabled = True
End Sub
Public Shared Sub UdpateText(ByVal sender As Object, ByVal e As System.EventArgs)
counter += 1
instance.UpdateText(String.Format("Updated {0} time(s).", counter))
End Sub
End Class

Run function if there is no action on form for some time

How do I fire an event/run function in vb.net if there is no action on form?
I have tried with this:
Private Sub Window_MouseMove(sender As Object, e As MouseEventArgs)
mint_LastInitializedTimerID = mint_LastInitializedTimerID + 0.00000001
Dim intMilliseconds As Integer = 5000
Dim objTimer As New System.Timers.Timer(intMilliseconds)
AddHandler objTimer.Elapsed, AddressOf Window_TimerElapsed
objTimer.AutoReset = False
objTimer.Enabled = True
End Sub
Private Sub Window_TimerElapsed(ByVal sender As Object, ByVal e As System.Timers.ElapsedEventArgs)
mint_LastReceivedTimerID = mint_LastReceivedTimerID + 0.00000001
If mint_LastReceivedTimerID = mint_LastInitializedTimerID Then
Me.Dispatcher.Invoke(Sub() showLogin(), System.Windows.Threading.DispatcherPriority.Normal)
End If
End Sub
Public Function showLogin()
WinUIMessageBox.Show(Window.GetWindow(Me), "!", "...", CType("1", MessageBoxButton), MessageBoxResult.None, MessageBoxOptions.None)
End Function
But for some reason, first time it works ok and next time it fires up function alot of times.
You can use IMessageFilter and Application.AddMessageFilter to determine when the user types or uses the mouse anywhere in your application. Have your custom filter class raise a custom event that your main form (or something else) traps. Quick example...
Public Class Form1
Private WithEvents mmf As MyMessageFilter
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
mmf = New MyMessageFilter(TimeSpan.FromSeconds(5))
Application.AddMessageFilter(mmf)
End Sub
Private Sub mmf_UserIdle() Handles mmf.UserIdle
Me.Text = "User Idle # " & DateTime.Now
End Sub
Private Class MyMessageFilter
Implements IMessageFilter
Private Enum UserActivity
WM_KEYDOWN = &H100
WM_KEYUP = &H101
WM_SYSKEYDOWN = &H104
WM_SYSKEYUP = &H105
WM_MOUSEMOVE = &H200
WM_LBUTTONDOWN = &H201
WM_LBUTTONUP = &H202
WM_RBUTTONDOWN = &H204
WM_RBUTTONUP = &H205
End Enum
Public Event UserIdle()
Private WithEvents tmr As New System.Timers.Timer()
Private SC As System.Threading.SynchronizationContext
Private Sub New()
End Sub
Public Sub New(ByVal TimeOutDuration As TimeSpan)
SC = System.Windows.Forms.WindowsFormsSynchronizationContext.Current
tmr.Interval = TimeOutDuration.TotalMilliseconds
tmr.Start()
End Sub
Private Sub Reset()
tmr.Stop()
tmr.Start()
End Sub
Private Sub tmr_Elapsed(ByVal sender As Object, ByVal e As System.Timers.ElapsedEventArgs) Handles tmr.Elapsed
' raise the event in a thread safe manner
If Not IsNothing(SC) Then
SC.Post(New System.Threading.SendOrPostCallback(AddressOf GuiSafeRaiseEvent), Nothing)
End If
End Sub
Private Sub GuiSafeRaiseEvent() ' do not call me directly!
RaiseEvent UserIdle()
End Sub
Private Function PreFilterMessage(ByRef m As System.Windows.Forms.Message) As Boolean Implements System.Windows.Forms.IMessageFilter.PreFilterMessage
Select Case m.Msg
Case UserActivity.WM_KEYDOWN, UserActivity.WM_KEYUP, UserActivity.WM_LBUTTONDOWN, UserActivity.WM_LBUTTONUP, UserActivity.WM_MOUSEMOVE, UserActivity.WM_RBUTTONDOWN, UserActivity.WM_RBUTTONUP, UserActivity.WM_SYSKEYDOWN, UserActivity.WM_SYSKEYUP
Me.Reset() ' the user did something, reset the timer
End Select
Return False ' allow normal processing to occur for all messages
End Function
End Class
End Class
I think you're creating a new handler every millisecond that the mouse is in motion. I'd think you would want to create the timer when the form loads, then reset it to 0 each time the mouse moves.
Another option would be similar to this post https://stackoverflow.com/a/44552767/5162073. You can respond as needed after any amount of idle time.
If a.GetIdleTime() > 300 Then
showLogin()
End If

VB.net AddHandler with index

I have a multithread program that download info from the internet off different proxies. I have it working fine but I have to add functions for each thread so that I know which thread is being processed. so if I want 10 thread I need 10 functions named processItems0 processItems1 processItems2 and so on. All my processItems0 function does is pass the data to another function with a index. I wish I could do something thing like processItems(0) so that I can have 1 function and didn't need a stack of if statements to track which webclient the data is coming from. I want it to support 100 thread if i wanted it to. what im doing works but it cant be the best way. Thanks in advance
Dim wc As New WebClient
''' if statements that i want to get rid of
If wcn = 0 Then
AddHandler wc.UploadStringCompleted, AddressOf processItems0
ElseIf wcn = 1 Then
AddHandler wc.UploadStringCompleted, AddressOf processItems1
end if
wc.Proxy = wp(wcn)
Dim u As New Uri(laurl)
wc.UploadStringAsync(u, data)
''' individual functions for each webclient i want to run.. t
Private Sub processItems0(ByVal sender As Object, ByVal e As UploadStringCompletedEventArgs)
If e.Cancelled = False AndAlso e.Error Is Nothing Then
processData(CStr(e.Result), 0)
End If
End Sub
Private Sub processItems1(ByVal sender As Object, ByVal e As UploadStringCompletedEventArgs)
If e.Cancelled = False AndAlso e.Error Is Nothing Then
processData(CStr(e.Result), 1)
End If
End Sub
Private Sub processData(data As String, wcn As Integer)
'process data
end Sub
Please remember to remove your event handlers to prevent memory leaks.
Public Class ProxyWrapper
Inherits WebClient
Private _index As Integer
Public Sub New(ByVal index As Integer)
_index = index
End Sub
Public ReadOnly Property Index As Integer
Get
Return _index
End Get
End Property
Public Sub RegisterEvent()
AddHandler Me.UploadStringCompleted, AddressOf processItems
End Sub
Public Sub UnregisterEvent()
RemoveHandler Me.UploadStringCompleted, AddressOf processItems
End Sub
Private Sub ProcessItems(ByVal sender As Object, ByVal e As UploadStringCompletedEventArgs)
If e.Cancelled = False AndAlso e.Error Is Nothing Then
ProcessData(CStr(e.Result), _index)
End If
End Sub
Private Sub ProcessData(ByVal res As String, ByVal index As Integer)
' Handle data
End Sub
End Class

Cancel Datetimepicker ValueChanged Event

Is there a way to cancel an event through a condition? I have tried e.cancel but it does not work. After cancelling the event the dtpAudit_From.Value must revert back to its original value.
Private Sub dtpAudit_From_ValueChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles dtpAudit_From.ValueChanged
'check if two DTPs (Date time pickers) are valid
If dtpAudit_From.Value > dtpAudit_To.Value Then
MsgBox("cancel the event")
End If
End Sub
One way is to subclass the DateTimePicker and add a ValueChanging event. Here's an example:
Public Class UIDateTimePicker
Inherits DateTimePicker
Public Sub New()
Me.cachedValue = Me.Value
End Sub
Public Event ValueChanging As CancelEventHandler
Protected Overrides Sub OnValueChanged(e As EventArgs)
If (Not Me.reverting) Then
Dim evargs As New CancelEventArgs(False)
Me.OnValueChanging(evargs)
If ((Not evargs Is Nothing) AndAlso evargs.Cancel) Then
Dim value As Date = Me.Value
Me.reverting = True
Me.Value = Me.cachedValue
Else
Me.cachedValue = Value
MyBase.OnValueChanged(e)
End If
Me.reverting = False
End If
End Sub
Protected Overridable Sub OnValueChanging(e As CancelEventArgs)
RaiseEvent ValueChanging(Me, e)
End Sub
Private cachedValue As DateTime
Private reverting As Boolean
End Class
Usage
Private Sub dtpAudit_From_ValueChanging(sender As Object, e As CancelEventArgs) Handles dtpAudit_From.ValueChanging
e.Cancel = {Condition}
End Sub