【发布时间】:2020-11-19 11:47:44
【问题描述】:
我创建了一个类用作通知窗口(类似于 toast 通知,在我们的系统上已禁用)。 我使用一个计时器对象来超时关闭表单,并使用一个后台工作者来处理它从屏幕底部滑入的动画。出于调试目的,表单只输出它自己的大小和屏幕边界。
Imports System.ComponentModel
Public Class ASNotify
Public Sub New(ByVal title As String, ByVal msg As String, ByVal Optional timeout As Integer = 5000)
' This call is required by the designer.
InitializeComponent()
' Add any initialization after the InitializeComponent() call.
Me.Text = title
Me.NotifyMessage.Text = $"{Me.Width}x{Me.Height}{vbCrLf}{My.Computer.Screen.WorkingArea.Size.Width}x{My.Computer.Screen.WorkingArea.Size.Height}"
TimeoutTimer.Interval = timeout
TimeoutTimer.Enabled = True
AnimationWorker.RunWorkerAsync()
End Sub
Private Sub AnimationWorker_DoWork(sender As Object, e As DoWorkEventArgs) Handles AnimationWorker.DoWork
Dim xloc As Integer = My.Computer.Screen.WorkingArea.Size.Width - Me.Width
Dim yloc As Integer = My.Computer.Screen.WorkingArea.Size.Height
For x As Integer = 0 To Me.Height
MoveWindow(xloc, yloc - x)
Threading.Thread.Sleep(2)
Next
End Sub
Private Sub MoveWindow(xloc As Integer, yloc As Integer)
If InvokeRequired Then
Invoke(Sub() MoveWindow(xloc, yloc))
Else
Location = New Drawing.Point(xloc, yloc)
End If
End Sub
Private Sub TimeoutTimer_Tick(sender As Object, e As EventArgs) Handles TimeoutTimer.Tick
Me.Close()
End Sub
End Class
我通过调用从另一个表单调用它
Private Sub NotifyUser(ByRef a As Alert.Alert)
Dim notify As New ASNotify(a.Location, a.Comment, 5000)
notify.Show()
End Sub
我通过按下表单上的一个按钮来调用那个 sub,它可以完美地工作.....有时。
反复触发通知窗口使其在屏幕上弹出为 2 种不同尺寸之一,尽管显示尺寸的内容始终为 264x81 且屏幕边界为 1920x1040
偶尔我会收到一个异常,即“Location = new Drawing.Point(xloc,yloc) 是从创建它的线程之外的线程调用的,尽管调用了 Invoke。
【问题讨论】:
-
为什么不直接使用 Timer 来执行转换?无论如何,您都在调用(尝试)UI 线程。如果您真的想使用 BackgroundWorker,请使用其
DoWorkEventArgs将表单的高度传递给 DoWork 处理程序,然后在其 ProgressChanged 处理程序中更新位置:该事件在 UI 线程中引发,因此无需担心调用(如果需要调用UI Thread,调用BeginInvoke(),不需要InvokeRequired)。 -
并没有完全解决我的问题,但重写以使用 begininvoke,并阅读产生的错误导致我找到了解决方案。进行呼叫时,窗口并未完全实现。将动画和计时器移至 Load 方法,而不是 New 方法,现在可以使用了。
标签: vb.net multithreading forms