C# 按钮 - 多个方法调用
本文关键字:方法 调用 按钮 | 更新日期: 2023-09-27 18:22:21
一个基本的C#问题。
我的表单上有两个禁用的文本框和一个按钮。该按钮当前如下所示:
private void start_Click(object sender, EventArgs e)
{
this.two();
this.hold();
this.one()
}
如您所见,它调用了其他三种方法,如下所示:
- "two" - 使两个文本框都为背景色、黑色。
- "一" - 只制作其中一个框 背景颜色 黑色。
- "拿">
- 调用"System.Threading.Thread.Sleep(1000(;"以暂停程序一秒钟。
- 将两个文本框的背景色更改回白色。
我遇到的问题是程序似乎跳过了第一个调用到两个。只需按住程序一秒钟,然后将一个文本框更改为黑色。
感谢您的任何帮助!
您可能遇到的是,您在应用程序的主线程上运行此代码,该线程还负责响应 Windows GUI 消息(如更改文本框颜色后重新绘制自身的命令(。程序当前不会处理此消息,直到此事件处理程序完全执行后,此时只有一个文本框是黑色的。
如前所述,Application.DoEvents(( 将通过中断此处理程序并允许程序在继续之前处理来自 GUI 的排队消息来解决问题。执行此操作的另一种方法是在 BackgroundWorker 中运行此代码,该线程将使用单独的处理线程来告诉 GUI 线程重新着色文本框,同时不使用 Sleep(( 命令阻止 GUI 线程。通常,使用多线程方法更好,因为 Application.DoEvents(( 可能会在当前事件处理程序尚未完成时强制调用其他事件处理程序,从而导致意外后果(例如,对引发异常的另一个事件处理程序的调用将通过您中断的那个 Application.DoEvents 调用抛出,这实际上没有问题(。
正如其他人提到的,这是因为您的 UI 线程在开始刷新显示之前开始休眠。
切勿在 UI 线程上调用Thread.Sleep
。它会"阻止"你的程序并激怒你的用户。如果你有一些需要Thread.Sleep
的工作要做,创建一个新线程,但不要在 UI 线程中执行此操作。
它不会跳过对two
的调用,但由于您通过调用Thread.Sleep
来阻止 UI 线程,因此 UI 永远不会有机会刷新以显示two
的效果。
你可以做这样的事情:
private void start_Click(object sender, EventArgs e)
{
this.two()
Task.Factory.StartNew(() => this.hold())
.ContinueWith(_ => this.one(), TaskScheduler.FromCurrentSynchronizationContext());
}
它将在新线程中执行hold
(因此不会冻结 UI(,然后在hold
完成后,它将在 UI 线程上执行two
。
试试这个:
private void start_Click(object sender, EventArgs e)
{
this.two();
Application.DoEvents();
this.hold();
this.one();
}
调用 DoEvents();
允许窗口在单击处理程序的中间重新绘制,而不是等到完成。
编辑:请阅读对此答案的评论...您会发现执行这样的阻止操作是"不好的做法"。
由于您在 UI 线程上执行Thread.Sleep
,因此您的表单没有机会更新自身并使用新颜色重新绘制。
您可以在hold
之前引入Application.DoEvents
调用;但是,正如其他人指出的那样,这将导致您的UI线程在一秒钟的延迟内保持冻结状态(并且对用户活动无响应(。
在逻辑中引入延迟的最佳方法是使用 Timer
。下面是一些在延迟一秒后two
执行的示例代码。
Timer timer = new Timer { Interval = 1000 };
timer.Tick += (sender, e) =>
{
this.Invoke(new Action(two));
timer.Stop();
timer.Dispose();
};
timer.Start();