我正在使用Mono测试我的应用程序,以便进行Linux端口,但我遇到了一个线程问题。最初我考虑在此处粘贴3000行代码,但最终我设计了一个小的最小示例;)
您有一个带有按钮(诗意地命名为Button1
)和标签(不出所料,名称为Label1
)的窗体。整个窗体位于名为Form1
的表单上,并且单击Button1
会启动一个无限循环,该循环会递增本地计数器并更新Label1
(使用Invoke
)以反映其值。
现在,在Mono中,如果调整窗体大小,则标签将停止更新,永远不会重新启动。这在MS实现中不会发生。 BeginInvoke
也不起作用;更糟糕的是,它会使UI在两种情况下挂起。
您知道这种差异来自哪里吗?你会如何解决它?最后,为什么这里BeginInvoke
不起作用?我一定犯了一个很大的错误...但是是什么呢?
编辑:: 目前为止有一些进展:
- 实际上,调用BeginInvoke确实起作用;只是UI刷新得不够快,因此似乎会停止。
- 在mono中,当您向UI队列中插入消息(例如通过调整窗体大小)时,整个线程都会挂起。实际上,同步的
Invoke
调用从未返回。我正在努力理解原因。 - 值得注意的是:即使是使用
BeginInvoke
,异步调用也不会在调整大小操作结束之前执行。在MS.Net上,它们在调整大小时继续运行。
代码如下(C#版本较低):
Public Class Form1
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim T As New Threading.Thread(AddressOf Increment)
T.Start()
End Sub
Sub UpdateLabel(ByVal Text As String)
Label1.Text = Text
End Sub
Delegate Sub UpdateLabelHandler(ByVal Text As String)
Sub Increment()
Dim i As Long = 0
Dim UpdateLabelDelegate As New UpdateLabelHandler(AddressOf UpdateLabel)
Try
While True
i = (i + 1) Mod (Long.MaxValue - 1)
Me.Invoke(UpdateLabelDelegate, New Object() {i.ToString})
End While
Catch Ex As ObjectDisposedException
End Try
End Sub
End Class
或者,在C#中,
public class Form1
{
private void Button1_Click(System.Object sender, System.EventArgs e)
{
System.Threading.Thread T = new System.Threading.Thread(Increment);
T.Start();
}
public void UpdateLabel(string Text)
{
Label1.Text = Text;
}
public delegate void UpdateLabelHandler(string Text);
public void Increment()
{
long i = 0;
UpdateLabelHandler UpdateLabelDelegate = new UpdateLabelHandler(UpdateLabel);
try {
while (true) {
i = (i + 1) % (long.MaxValue - 1);
this.Invoke(UpdateLabelDelegate, new object[] { i.ToString() });
}
} catch (ObjectDisposedException Ex) {
}
}
}