我有一个UserControl,我在其上添加了一个System.Windows.Forms.Timer。计时器是在设计时添加的。默认情况下,Enabled属性为False。我刚把它的间隔改为400毫秒。
UserControl以编程方式添加到表单中。计时器在设计时被禁用。在运行时,计时器由UserControl的Property Setter启用。
UserControl类是这样的:
Public Class LuminaireSign
Public Property MyLuminaire As Luminaire
Private _state As LuminaireSignState
Public Property State As LuminaireSignState
Get
Return _state
End Get
Set(value As LuminaireSignState)
If value <> _state Then
_state = value
If _state = LuminaireSignState.OK Then
Timer1.Enabled = False
Me.Image = luminSign_Green
Else
Timer1.Enabled = True
End If
End If
End Set
End Property
Public Sub New(ByRef associatedLumin As Luminaire)
' This call is required by the designer.
InitializeComponent()
' Add any initialization after the InitializeComponent() call.
MyLuminaire = associatedLumin
AddHandler MyLuminaire.PropertyChanged, New PropertyChangedEventHandler(AddressOf propChanged)
End Sub
Private Sub propChanged(sender As Object, e As PropertyChangedEventArgs)
If e.PropertyName = "Status" Then
If MyLuminaire.Status.BatteryEmpty Then
State = LuminaireSignState.Fault
Else
State = LuminaireSignState.OK
End If
End If
End Sub
奇怪的是,即使计时器获得启用,计时器的Tick事件也不会被触发。
如您所见,我通过Sub propChanged()设置State属性,它是一个处理MyLuminaire.PropertyChanged的PropertyChangedEventHandler。 MyLuminaire在UserControl的构造函数中通过引用传递。实际灯具对象的状态在非UI线程中设置。
难道不能勾选,因为propChanged事件是通过非UI线程属性更改触发的吗? 有人可以解释一下发生了什么吗?
PS。如果我在设计时启用计时器,则Tick事件会一直触发,直到计时器被禁用一次。然后,即使计时器变为启用,它也不会触发Tick事件。
答案 0 :(得分:0)
问题是propertyChanged发生在后台线程中,因此计时器无法触发Tick事件。所以我们必须以线程安全的方式启用计时器!
解决方案是不直接设置timer1.Enabled,而是创建一个子(请参阅SetStateOk),设置timer1和每当InvokeRequired = true时调用此子的委托。
因此,更改State属性并添加一个调用SetStateOk Sub并解决问题:
Public Property State As LuminaireSignState
Get
Return _state
End Get
Set(value As LuminaireSignState)
If value <> _state Then
_state = value
If _state = LuminaireSignState.OK Then
SetStateOk(true)
'Timer1.Enabled = False
'Me.Image = luminSign_Green
Else
SetStateOk(false)
'Timer1.Enabled = True
End If
End If
End Set
End Property
Private Delegate Sub SetStateOKDelegate(ByVal stateIsOk As Boolean)
Private Sub SetStateOK(ByVal stateIsOk As Boolean)
If Me.InvokeRequired Then
Me.Invoke(New SetStateOKDelegate(AddressOf SetStateOK), New Object() {stateIsOk})
Else
If stateIsOk Then
timer1.Enabled = False
Image = luminSign_Green
Else
timer1.Enabled = True
End If
End If
End Sub
通过这种方式启用计时器并定期触发Tick事件!