Vb.net System.Timers.Timer和数据绑定
如果我有一个实现INotifyPropertyChanged的类,并且该类中有一个绑定到表单标签的属性,那么如果我从System.Timers.Timer.Appeased事件处理程序设置属性值,如何避免出现跨线程异常 下面的代码演示了该异常Vb.net System.Timers.Timer和数据绑定,vb.net,Vb.net,如果我有一个实现INotifyPropertyChanged的类,并且该类中有一个绑定到表单标签的属性,那么如果我从System.Timers.Timer.Appeased事件处理程序设置属性值,如何避免出现跨线程异常 下面的代码演示了该异常 Imports System.ComponentModel Imports System.Timers Public Class Form1 Private thisClass As New aClass Private Wit
Imports System.ComponentModel
Imports System.Timers
Public Class Form1
Private thisClass As New aClass
Private WithEvents tmr As New System.Timers.Timer()
Private lbl As System.Windows.Forms.Label
Public Sub New()
InitializeComponent()
'create the label and add it to the form
lbl = New Label
lbl.Text = "some text"
Me.Controls.Add(lbl)
'set the data binding and start a timer
lbl.DataBindings.Add("Text", thisClass, "X")
tmr.Interval = 1000
AddHandler tmr.Elapsed, AddressOf tmr_Elapsed
tmr.Start()
End Sub
Private Sub tmr_Elapsed(sender As Object, e As ElapsedEventArgs)
'change the property value when the timer elapses
thisClass.X = Guid.NewGuid.ToString
End Sub
End Class
Public Class aClass
Implements INotifyPropertyChanged
Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged
Private _x As String = ""
Public Property X As String
Get
Return _x
End Get
Set(value As String)
_x = value
RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs("X"))
End Set
End Property
End Class
另一种方法是使用异步方法在同一线程上不断更新代码
Public Class MyForm
Private _viewmodel As MyViewModel
Private _intervalTask As Task
Private _canContinueIntervalRunning As Boolean
Public Sub New()
InitializeComponent()
_viewmodel = New MyViewModel()
CreateLabel() ' Create label and bind to viewmodel property
' Start interval without blocking this code execution
' Later we can use this saved task to make sure that task is complete
_canContinueIntervalRunning = True
_intervalTask = StartInterval()
End Sub
Private Async Function StartInterval() As Task
While _canContinueIntervalRunning
Await Task.Delay(1000)
_viewmodel.X = Guid.NewGuid().ToString()
End While
End Function
Private Async Sub FormClosing(sender as Object, e as FormClosingEventArgs) Handles MyForm.FormClosing
' Set "flag" to false and wait for task to complete
_canContinueIntervalRunning = False
Await _intervalTask
End Sub
End Class
使用wait Task.Delay(1000)
下一行将在同一个线程上执行,这允许在不需要额外努力的情况下更新表单控件
这是使用布尔标志的简单方法,另一种方法是使用取消令牌,您可以将其传递给
任务。延迟
-然后表单不需要等待额外的秒,但是可以立即取消延迟
。是否有理由使用系统.Timers.Timer
而不是系统.Windows.Forms.Timer
?如果您确实有一个,请使用Me.Invoke(新操作(Sub()thisClass.X=Guid.NewGuid.ToString())
。如果没有,只需切换到System.Windows.Forms.Timer
,其Tick
事件在主(UI)线程上运行。@41686d6564的重复项-我是否必须使用系统计时器,否,但在这种情况下,窗体计时器将浪费UI时间片。另外,我不认为这个问题是重复的。在您的重复文章中,很明显需要调用。有了数据绑定,就没有机会调用“不,我没有”,那么,请这样做。将thisClass.X=Guid.NewGuid.ToString
行替换为我第一条评论中的代码,如果它不起作用,请告诉我(扰流板警报:它会起作用)。我很清楚您使用的是数据绑定,我在上面解释了引发异常的原因,以及使用Invoke()
将如何防止这种情况。如果你还有任何问题,请告诉我。我很乐意帮忙:)“在这种情况下,表单计时器会浪费UI时间片”。显然,如果您需要在事件处理程序中做的唯一一件事是影响UI,那么就不会发生。任何影响UI的操作都必须在UI线程上执行。任何必须在UI线程上执行的操作都不会浪费UI线程的时间。