how to automatically disable a button in vb.net - vb.net

how to automatically disable a button for a period of time in vb.net?
my project is voting management using vb.net and Sql server .my voting starts only from 9 am-10 am .so the button which i log in should automatically disable before and after the given time.

Run a Thread on start-up which from this point on should loop forever. Check the DateTime.Now to check what time it is currently. Enable and Disable it if the time is between your allotted times. Then calculate how long you need to wait before the end of the window, put the thread to sleep for that amount of time.
Edit: example code
Make sure you include this at the top. Imports System.Threading
Private Sub Window_Loaded(sender As Object, e As RoutedEventArgs)
Dim myThread As System.Threading.Thread
myThread = New System.Threading.Thread(AddressOf ThreadLoop)
myThread.Start()
End Sub
Private Sub ThreadLoop()
While True
Dispatcher.Invoke(
Sub() myButton.IsEnabled = (DateTime.Now.Hour = 9))
Thread.Sleep(10000) ' This implementation just rechecks every 10 seconds
End While
End Sub
Note: This solution automatically updates the UI when the time changes.

In your form/page loading, use DateTime to get the current hour:
Dim currentDate As System.DateTime
Dim currentHour As Integer
currentDate = Date.Now()
currentHour = currentDate.Hour
If currentHour = 9 Or currentHour = 10 Then
button.Visible = False
Endif

Related

Scheduled Notifications in Windows 10 VB.Net

I am working on a project where the user sets a reminder with information, date and time for when a notification should pop up and the notification should be clickable and open another form with the reminder information on it. So far I can set the reminder but it pops up as soon as the remind button in clicked, my notification looks a standard windows 10 notification, I just want the notification to be scheduled for a certain date and time. The information including date and time is saved into an Access Database. I am using VB.Net
Kind Regards
Form:
This is my reminder form as of now
This is how my notification looks like
Imports System.Data.OleDb
Public Class frmReminder
Private CurrentReminderID As Integer = -1
Private Sub frmReminder_Load(sender As Object, e As EventArgs) Handles MyBase.Load
BtnClear.PerformClick()
Timer1.Enabled = True
End Sub
Private Sub BtnClear_Click(sender As Object, e As EventArgs) Handles BtnClear.Click
Label6.Text = ""
TxtCustName.Text = ""
TxtDeviceInfo.Text = ""
TxtPrice.Text = ""
TxtDateDue.ResetText()
End Sub
Private Sub BtnSetReminder_Click(sender As Object, e As EventArgs) Handles BtnSetReminder.Click
If DbConnect() Then
Dim SQLCmd As New OleDbCommand
If CurrentReminderID = -1 Then
With SQLCmd
.Connection = cn
.CommandText = "Insert into TblReminder (CustomerName, DeviceInfo, RepairPrice, ReminderDate)"
.CommandText &= "Values (#CustomerName, #DeviceInfo, #RepairPrice, #ReminderDate)"
.Parameters.AddWithValue("#CustomerName", TxtCustName.Text)
.Parameters.AddWithValue("#DeviceInfo", TxtDeviceInfo.Text)
.Parameters.AddWithValue("#RepairPrice", TxtPrice.Text)
.Parameters.AddWithValue(" #ReminderDate", TxtDateDue.Text)
.ExecuteNonQuery()
.CommandText = "Select ##Identity"
CurrentReminderID = .ExecuteScalar
Label6.Text = CurrentReminderID
End With
End If
End If
Notification.ShowBalloonTip(1000, "Reminder", "Customer Order Due!", ToolTipIcon.None)
End Sub
End Class
You need to use a Timer and to avoid the constant reading of the database you may use something very simple as a DateTimePicker or a TextBox. In this example I'll use a Texbox.
So, insert a TextBox1 in your form and had the value of the first date/time (read from your database just once). The Textbox1 text should be something like "2021-10-21 15:00" (don't put the seconds and don't forget to have a space between date and time)
TextBox1.Text="2021-10-21 15:00" ' read this data from your database
Then you need to insert a Timer in your form and add this values:
Timer1.Interval = 60000 ' 1 minute
Timer1.Enabled = True
For the last you need to double click the Timer1 and write this code:
Private Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick
If TextBox1.Text = Now.ToString("yyyy-MM-dd HH:mm") Then
' At this moment you should read the next date/time and put that in TextBox1
MsgBox("Show the popup notification")
End If
End Sub
Since you are using DB connections, ill assume you are familiar with multi threading.
RULE 1. The easiest way to do this is for your application to keep track of (in RAM) the next notification. Any time you add a new one through your app it will both insert it into the DB as well as check to see if it is going to elapse before the current one in RAM. When the one in RAM expires it grabs the next one from the DB. All that to say, you find a way to ensure that the next one to elapse is kept in RAM at any given time.
RULE 2. Then, when a notification is 'saved' in RAM, compare the time when the notification should be displayed - current time, this will give you how long until the notification should de shown and set a timer for that amount of time.
RULE 3. When the timer has elapsed display the notification for the one that is in RAM (Per rule 1 this is the one that just elapsed). And iterate the DB to find the next one to expire. Rinse and repeat. (Note, youll need to handle edge cases for when the first one is intered as there will not be any to compare to, and for when the last one is notified as there will not be any notifications left to store in RAM)
Tada, sorry i dont have code samples. But that is how i have solved this very issue numerous times. It works quite nicely.
EDIT 1: CODE
'main for testing
Dim notificationScheduler As NotificationScheduler = NotificationScheduler.getInstance
notificationScheduler.insertNotification(New MyNotificationEntity("Yay, working", DateTime.Now.AddSeconds(15)))
' expected that the one below will be displayed since insertNotification will only keep track of the newest one in the queue
' As mentioned in your post, you have a DB to persist them long term and as such will only need one in the APP's RAM at a time
notificationScheduler.insertNotification(New MyNotificationEntity("Yay, working-2", DateTime.Now.AddSeconds(3)))
' myNotificationEntity, will be replaced by whatever class you are using to package your reminder's in a single class (dont see on in your code sample)
Public Class MyNotificationEntity
Public data As String
Public timeToShow As DateTime
' this is a dumb bucket class, you will not end up using this one but rather whatever class you use to contain your notifications
' you will need to add _timeToShow as a variable to your class or change the code in the NotificationScheduler to be compatible with your Notification class
Public Sub New(data As String, timeToShow As DateTime)
Me.data = data
Me.timeToShow = timeToShow
End Sub
End Class
'NotificationScheduler class
Public Class NotificationScheduler
Private Shared _instance As NotificationScheduler
Private Shared ReadOnly _lock As Object = New Object()
Dim queuedNotification As MyNotificationEntity
Dim WithEvents timer As System.Windows.Forms.Timer = New Timer
Dim timerElapsedTime As DateTime = DateTime.Now
Private Sub New()
timer.Enabled = False
End Sub
Public Shared Function getInstance()
' enforce singleton design pattern (i.e. there should only be one of these in existence)
' If this does not make sense, that is fine, at some point lookup the 'singleton design pattern'
' Also, SyncLock is a VB (.net really) element that means in a multi-threaded application only one of them at any given time is inside the SyncLock block,
' the rest are queued to alleviate race conditions. Again, if this does not make sense, lookup 'race conditions'
SyncLock _lock
If (_instance Is Nothing) Then
_instance = New NotificationScheduler()
End If
End SyncLock
Return _instance
End Function
' called after you have placed the new notification in your DB, replaces the currently queued notification only if the new one will be shown first
Public Sub insertNotification(notificationEntity As MyNotificationEntity)
If timerElapsedTime.Ticks < notificationEntity.timeToShow.Ticks Then
queuedNotification = notificationEntity
timer.Stop()
Dim span As TimeSpan = notificationEntity.timeToShow - timerElapsedTime
timer.Interval = CInt(span.TotalMilliseconds)
timer.Start()
End If
End Sub
Private Sub timer_elapsed() Handles timer.Tick
' the notification time has arrived
showNotification()
readNextFromDb()
End Sub
Private Sub readNextFromDb()
' read the next (if any) from the and handle edge cases for when there is not next one in the DB
'IMPORTANT: if the one you read from the DB has already happened (i.e. the notification dateTime is after now, notify and do this method again)
'' your code here
End Sub
Private Sub showNotification()
MsgBox(queuedNotification.data) ' do whatever notification you want
End Sub
End Class
You will need to (it appears) create a class NotificationDAO (Data Access Object) or NotificationDTO (Data Transfer Object) or a generic NotificationEntity. That class will have a constructor and public instance variables for the items you need to store about a notification (i.e. every column you have in the 'TblReminder ' table) and everything should work fairly easily.
Note, the above code does not work nor check for pulling notifications out of a DB that have already passed their notification time, read the comments in the code for further information.

Open multiple URLs successively in WebBrowser control in VB.NET

I'm trying to make a "rotator" on a form that cycles through a series of urls and displays the url in the WebBrowser control. The following code displays my form, but the form remains white/blank and then the last url in the array appears after a while. When I put a MessageBox in-between each url, to create a stop, it works and each url appears. I've tried putting a Sleep in place of the MessageBox, but that didn't work. I've also tried increasing the Sleep time, but that didn't work either. How can I make it work correctly?
Sub Rotate()
Dim Urls() As String = {"www.stackoverflow.com", "www.google.com", "www.yahoo.com"}
Dim counter As Integer = 0
Form3.Show()
Do Until counter = 3
Form3.WebBrowser1.ScriptErrorsSuppressed = True
Form3.WebBrowser1.Navigate(Urls(counter))
'MessageBox.Show("Next")
counter = counter + 1
System.Threading.Thread.Sleep(2000)
Loop
End Sub
You can call Application.DoEvents after changing the URL so that the control gets the chance to redraw itself.
However, a better approach would be to use a timer which fires every 2 seconds and then change the URL in the event handler so that your UI keeps responsive.
For example setup a new field myTimer in your form, init it in your form's loading event and in the Tick event you call your Rotate method. As Rotate is now called several times, we have to move the counter variable out of the method and make it a field so that we keep its value between the invocations. I usually write C# so hopefully I did not make some typos below :)
Private WithEvents myTimer As System.Windows.Forms.Timer
Private counter As Integer
Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
' ... your existing code ...
counter = 0
myTimer = New System.Windows.Forms.Timer
myTimer.Interval = 2000
myTimer.Enabled = True
myTimer.Start()
End Sub
Private Sub myTimerTick() Handles myTimer.Tick
Rotate()
End Sub
Sub Rotate()
Dim Urls() As String = {"www.stackoverflow.com", "www.google.com", "www.yahoo.com"}
WebBrowser1.ScriptErrorsSuppressed = True
WebBrowser1.Navigate(Urls(counter))
counter = counter + 1
If counter > 3 Then myTimer.Stop()
End Sub

programing vb.net, Textbox in second form will not update

I am trying to create a timer that will countdown from the specified time.
The user enters a time and clicks a button.
The button click opens a second form that has a timer in it.
Every time the timer ticks, the time decreases and the time left is displayed in a textbox on form2 (textbox.text = timeLeft).
However, the textbox will never actually update. It remains blank, and the only time that assigning a new value to the .text property will actually work is if I raise an event (for example clicking a button that will change the .text property of the textbox)
*Here is the code for the timer class
Public Class CountdownTimer
Private timeAtStart As Integer
Private timeLeft As Integer
Public Sub StartTimer(ByVal time As Integer)
timeAtStart = time
timeLeft = timeAtStart
Timer1.Enabled = True
End Sub
Private Sub Timer1_Tick(ByVal sender As Object, ByVal e As System.EventArgs) Handles Timer1.Tick
If timeLeft > 0 Then
timeLeft = timeLeft - 1
txtTimeLeft.Text = timeLeft.ToString
Else
Timer1.Stop()
txtTimeRemaining.Text = "Time!"
txtTimeRemaining.ForeColor = Color.Red
End If
End Sub
End Class
And here is how I call it:
Dim timer As New CountdownTimer
timer.Show()
CountdownTimer.StartTimer(CInt(txtSetTime.Text))
Your code is calling the (form) class not the instance, and I cant see where Timer1 is properly referenced for an independant reusable class. Here is one way to implement a CountDown class that will work with other forms....
Friend Class CountdownTimer
Private timeAtStart As Integer
Private timeLeft As Integer
Private WithEvents Timer1 As New Timer
Private txtTimeLeft as TextBox
Public Sub New(TargetTB as TextBox)
txtTimeLeft= TargetTB
End Sub
Public Sub StartTimer(ByVal time As Integer, timeLength as Integer)
timeAtStart = time
timeLeft = timeLength
Timer1.Enabled = True
End Sub
Private Sub Timer1_Tick(ByVal sender As Object, ByVal e As System.EventArgs)_
Handles Timer1.Tick
' just dislaying time left
If timeLeft > 0 Then
timeLeft = timeLeft - 1
txtTimeLeft.Text = timeLeft.ToString
Else
Timer1.Stop()
txtTimeLeft.Text = "Time!"
txtTimeLeft.ForeColor = Color.Red
End If
End Sub
End Class
How to use it:
Dim CountDn As New CountdownTimer(frm.TextBoxToUse)
' use the INSTANCE name not the class name!!!!
'CountdownTimer.StartTimer(CInt(txtSetTime.Text))
CountDn.StartTimer(CInt(txtSetTime.Text))
If it displays the result after the timer has completed, i think you should use the
Application.DoEvents()
method to see the update immediately. It actually works with Windows Forms. What have you tried, so i can help further
You do realize that when you are counting down you are setting a different textbox than when it is complete, right?
txtTimeLeft.Text
VS
txtTimeRemaining.Text
Note: Timers run on the same thread as the UI so if you computer (or program) gets busy, the timer will NOT tick at exact intervals. If you are worried about small variances in your timer, you should compare the difference of your computer time during each tick event to determine how much time had passed.
Dim TS = TimeSpan = Now.Subtract(StartingTime)
Try refreshing the text boxes after each update:
So after
txtTimeLeft.Text = timeLeft.ToString
Add
txtTimeLeft.Refresh
This is your problem:
Dim timer As New CountdownTimer
timer.Show()
CountdownTimer.StartTimer(CInt(txtSetTime.Text))
You instantiate a new object called timer, but then start the timer on the CountdownTimer object
You need to change your code to this:
Dim timer As New CountdownTimer
timer.Show()
timer.StartTimer(CInt(txtSetTime.Text))

How do I call a function every x minutes in VB.NET?

How do I call a function every x minutes.
I assume I'd have to add a timer to the form?
here is a simple example:
Public Class SampleCallEveryXMinute
Private WithEvents xTimer as new System.Windows.Forms.Timer
Public Sub New(TickValue as integer)
xTimer = new System.Windows.Forms.Timer
xTimer.Interval = TickValue
End Sub
Public Sub StartTimer
xTimer.Start
End Sub
Public Sub StopTimer
xTimer.Stop
End Sub
Private Sub Timer_Tick Handles xTimer.Tick
SampleProcedure
End Sub
Private Sub SampleProcedure
'SomeCodesHERE
End Sub
End Class
USAGE:
Dim xSub as new SampleCallEveryXMinute(60000) ' 1000 ms = 1 sec so 60000 ms = 1 min
xSub.StartTimer
Yes, you could add a timer to the form, and set its interval to x*60000, where x is the number of minutes between calls.
Remember that the timer runs on the UI thread, so don't do anything intensive in the function. Also, if the UI thread is busy, the timer event will not fire until the UI thread finishes whatever event it is currently processing. If your function is going to be CPU-intensive, then consider having the timer start up a background worker
If you require a longer time period between function calls (ie, one thats too big for a timer interval) then you could have a timer function that fires every minute, and increments a counter until the desired amount of time has passed, before going on to call the function.
ALTERNATIVE 1
Here is good guide to use the Timer Control in VB.net.
The advantage is that you don't have to worry about modifying UI objects from non UI thread.
ALTERNATIVE 2
Another alternative is to spawn another thread and do the work and sleep the remaining x minutes.
The advantage here is that if your function doesn't touch UI objects your application will remain responsive to user input while the function is being called
Private Sub Form_Load()
_timer.Enabled = True
End Sub
Private Sub _timer_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer1.Tick
ListBox1.Items.Add(DateTime.Now.ToLongTimeString() + "," + DateTime.Now.ToLongDateString())
End Sub

vb.net Application.DoEvents() function halt and crash application in windows vista

i made an application for serial communication. for this application i need to set delay time. during this delay time i m doing some other task. So for those task i need to take back control from delay function, for this purpose i am unsing Doevents() function.Its work fine On other OS (XP, Windows7 32/64-bit). But Application.DoEvents() function halt and crash in windows vista.So is there any solution
Private Sub TimeDelay(ByVal DT As Integer)
Dim StartTick As Integer
StartTick = Environment.TickCount()
While ((Environment.TickCount() - StartTick) <= DT)
Application.DoEvents()
End While
'Application.DoEvents()
End Sub
thanks in advance
Try using a BackgroundWorker component instead of calling Application.DoEvents().
Please try System.Threading.Thread.SpinWait(10) after the Application.DoEvents, it might work.
I would recommend putting a "System.Threading.Thread.Sleep(1)" in the loop as well. It might happen because there are too many events pending for Windows to process, therefore ending in high CPU usage.
Sleeping 1 millisecond is very little (actually only 0,001 second). And it would decrease CPU usage dramatically as well, while still allowing the program to remain responsive.
The final code would be:
Private Sub TimeDelay(ByVal DT As Integer)
Dim StartTick As Integer
StartTick = Environment.TickCount()
While ((Environment.TickCount() - StartTick) <= DT)
Application.DoEvents()
System.Threading.Thread.Sleep(1)
End While
'Application.DoEvents()
End Sub
Try running this code:
TimeDelay(1000000)
You will notice that in the process, the program will consume almost 100% CPU with your code, but 0% with mine.
You shouldn't use DoEvents for this purpose.
Create a seperate thread to run the code you have provided. And use a call back (thread completed) to notify when the time has elapsed.
Imports System.Threading
Public Class Tester
Shared WithEvents oSquare As SquareClass = New SquareClass()
Public Shared Sub Main
Dim t As Thread
t = New Thread(AddressOf oSquare.TimeDelay)
t.Start()
End Sub
Shared Sub SquareEventHandler() Handles oSquare.ThreadComplete
Console.WriteLine("Completed")
End Sub
End Class
Public Class SquareClass
Public DT As Integer = 5000 ' 5 seconds (edited thanks to Mathias)
Public Event ThreadComplete()
Public Sub TimeDelay()
Dim StartTick As Integer
StartTick = Environment.TickCount()
While ((Environment.TickCount() - StartTick) <= DT)
thread.sleep(1000)
End While
RaiseEvent ThreadComplete()
End Sub
End Class