我正在做一个项目,用户设置一个提醒信息,日期和时间,当通知应该弹出,通知应该是可点击的,并打开另一个窗体上的提醒信息。到目前为止,我可以设置提醒,但是只要点击提醒按钮,它就会弹出,我的通知看起来像一个标准的windows 10通知,我只是想把通知安排在特定的日期和时间。包括日期和时间在内的信息被保存到Access数据库中。我用的是VB。净
亲切的问候
形式:
这是我目前的提醒表单
这是我的通知的样子
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
您需要使用计时器,为了避免数据库的不断读取,您可以使用一些非常简单的东西,如DateTimePicker或TextBox。在这个例子中,我将使用一个textbox
因此,在表单中插入一个TextBox1,并具有第一个日期/时间的值(仅从数据库读取一次)。Textbox1的文本应该类似于"2021-10-21 15:00"(不要写秒,不要忘记在日期和时间之间留个空格)
TextBox1.Text="2021-10-21 15:00" ' read this data from your database
然后你需要在你的表单中插入一个计时器,并添加以下值:
Timer1.Interval = 60000 ' 1 minute
Timer1.Enabled = True
最后,您需要双击Timer1并编写以下代码:
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
由于您使用的是数据库连接,我假定您熟悉多线程。
规则1。要做到这一点,最简单的方法是让应用程序(在RAM中)跟踪下一个通知。任何时候你通过你的应用程序添加一个新的,它将插入到数据库,以及检查,看看它是否会在内存中当前的一个之前失效。当RAM中的一个过期时,它会从DB中抓取下一个。总而言之,您可以找到一种方法来确保在任何给定时间将下一个要发生的事件保存在RAM中。
规则2。然后,当通知"保存"在RAM中时,比较通知应该显示的时间-当前时间,这将告诉您通知应该显示多长时间,并为该时间设置计时器。
规则3。当计时器经过时,显示RAM中计时器的通知(根据规则1,这是刚刚经过的计时器)。并迭代DB以找到下一个要过期的。清洗并重复。(注意,当第一个感兴趣时,你需要处理边缘情况,因为没有任何可以比较的,以及当最后一个通知时,因为没有任何通知留在RAM中存储)
Tada,对不起,我没有代码样本。但这就是我无数次解决这个问题的方法。它工作得很好。
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
您将需要(看起来)创建一个NotificationDAO(数据访问对象)或NotificationDTO(数据传输对象)类或一个通用的NotificationEntity。该类将有一个构造函数和公共实例变量的项目,你需要存储关于通知(即每列你有' tblremind '表),一切都应该相当容易工作。
注意,上面的代码不能工作,也不能检查从DB中提取通知是否已经经过了通知时间,请阅读代码中的注释以获取更多信息。