是的,花时间研究我知道
定时器是一个组件而不是一个控件,所以它不会位于 控制系列。这是一个可能更好的情况 使用常见的按钮单击处理程序,因为它没有简化 任何东西。 (Source)
但是,我能做些什么才能通过目前的情况?
我想要的是每当用户点击一个按钮(我有很多按钮)时,它将确定该按钮的状态是Start
还是Stop
,如果它是stop
它应该start
。
停止和启动对应于计时器,我拥有的按钮数量与我的计时器数量相对应。
我可以通过创建像这样的函数轻松链接它们
Function isBTNStatusEnabled(sender As Object) As Boolean
Dim result As Boolean = False
Dim btnStatus As Button = DirectCast(sender, Button)
Dim btnStatusNumber As String = btnStatus.Name.Substring(btnStatus.Name.Length - 1)
Console.WriteLine("Found the " & btnStatus.Name)
If btnStatus.Text = "Start" Then
btnStatus.Text = "Stop"
result = True
btnStatus.BackColor = Color.Red
Else
btnStatus.Text = "Start"
result = False
btnStatus.BackColor = SystemColors.Control
End If
For Each frmTesterObjects As Object In Me.components.Components
If TypeOf frmTesterObjects Is Timer And DirectCast(frmTesterObjects, Timer).Tag.ToString = "tmrString" & btnStatusNumber Then
'what to do
Console.WriteLine("Timer name: " & DirectCast(frmTesterObjects, Timer).Tag.ToString)
End If
Next frmTesterObjects
Return result
End Function
我的问题是这部分代码
If TypeOf frmTesterObjects Is Timer And DirectCast(frmTesterObjects, Timer).Tag.ToString = "tmrString" & btnStatusNumber Then
Console.WriteLine("Timer name: " & DirectCast(frmTesterObjects, Timer).Tag.ToString)
End If
我试图通过遍历表单中的所有对象来获取计时器的名称。我可以通过正确命名它们来轻松地对所有对象进行分组,例如在set 1
我有btnStatus1
和tmrString1
然后在set 2
我有btnStatus2
和{ {1}},只有最后一个数字字符串会发生变化。
答案 0 :(得分:1)
我刚刚简化了您的代码。这是:
For Each x In Me.components.Components.OfType(Of Timer)()
If x.Tag = "tmrString" & btnStatusNumber Then
Console.WriteLine("Timer name: " & x.Tag)
End If
Next
现在,您只需匹配与其Tag
对应的每个Timer
的{{1}}。
答案 1 :(得分:1)
我几乎总是发现,如果继续维护/修改表单,在运行时按名称搜索组件最终会失败。在我看来,确保你有一个编译时检查要好得多。
我会改为执行此代码:
Function isBTNStatusEnabled(sender As Object) As Boolean
Dim button2Timer = New Dictionary(Of Button, Timer) From
{{Button1, Timer1}, {Button2, Timer2}, {Button3, Timer3}}
Dim result As Boolean = False
Dim btnStatus As Button = DirectCast(sender, Button)
Console.WriteLine("Found the " & btnStatus.Name)
If btnStatus.Text = "Start" Then
btnStatus.Text = "Stop"
result = True
btnStatus.BackColor = Color.Red
Else
btnStatus.Text = "Start"
result = False
btnStatus.BackColor = SystemColors.Control
End If
Console.WriteLine("Timer name: " & button2Timer(btnStatus).Tag.ToString())
Return result
End Function
Dictionary(Of Button, Timer)
对映射进行硬编码,因此无需搜索Timer
。这也减少了实际命名和标记按钮和计时器的需要。
为了好玩,我根据你对这个问题的评论回答,实现了你的完整解决方案。这是:
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim parts =
{
New With {.Button = Button1, .NumericUpDown = NumericUpDown1, .TextBox = TextBox1, .Port = 1},
New With {.Button = Button2, .NumericUpDown = NumericUpDown2, .TextBox = TextBox2, .Port = 2},
New With {.Button = Button3, .NumericUpDown = NumericUpDown3, .TextBox = TextBox3, .Port = 3}
}
Dim query =
From p In parts
Select
Observable _
.FromEventPattern(Sub(h) AddHandler p.Button.Click, h, Sub(h) RemoveHandler p.Button.Click, h) _
.ObserveOn(Me) _
.Do(Sub(ep)
Dim start = p.Button.Text = "Start"
p.Button.Text = If(start, "Stop", "Start")
p.Button.BackColor = If(start, Color.Red, SystemColors.Control)
p.NumericUpDown.Enabled = Not start
p.TextBox.Enabled = Not start
End Sub) _
.Select(Function(ep) _
Observable _
.Interval(TimeSpan.FromSeconds(p.NumericUpDown.Value)) _
.Select(Function(n) New With {p.TextBox.Text, p.Port}) _
.TakeWhile(Function(x) p.Button.Text = "Stop")) _
.Switch()
query _
.Merge() _
.ObserveOn(Me) _
.Subscribe(
Sub(x)
TextBox4.Text = TextBox4.Text + String.Format("Text ""{0}"" on Port ""{1}""{2}", x.Text, x.Port, Environment.NewLine)
End Sub)
End Sub
我已经将Microsoft的Reactive Framework用于所有事件处理和计时器。您只需要在您的应用中使用NuGet“Rx-WinForms”即可使用它。
您会看到parts
包含按钮列表,数字上/下,文本框和端口号。
query
获取这些部分并为按钮点击创建处理程序。根据按钮内的文本,它会根据数字向上/向下控件和文本框启动计时器。查询只是以{ .Text = "Foo", .Port = 1 }
的形式生成值流。 <{1}}也使用query
运算符在计时器运行时更新UI。
最后,.Do(...)
代码会获取这些值,并在我的应用中将它们添加到表单上的文本框中,以便我可以看到所有输出。
以下是我使用它时的表单示例:
我希望这很有意思。