我有一些简单的C#代码,它们是在按下按钮时触发的。按下按钮首先清除一些ListBox,然后更改标签的文本,然后调用一个函数。
private void button1_Click(object sender, EventArgs e)
{
listBox1.Items.Clear();
listBox2.Items.Clear();
listBox3.Items.Clear();
listBox4.Items.Clear();
label5.Text = "Getting links...";
process(url);
label5.Text = "Finished";
}
但清除列表并在process()
执行完毕后更改标签。当我改变标签以便用户意识到某些动作正在发生时,这就破坏了目的。如何在函数process()
完成之前更改初始标签?
答案 0 :(得分:2)
如果您的process
方法长时间运行,可能会导致用户界面冻结并阻止重新绘制用户界面 - 这就是您没有看到标签文字立即更新的原因。
实现目标的最简单方法是在label5.Refresh()
之后立即调用label5.Text = "Getting links...";
,这将立即导致无效和重新绘制标签。
如果要更新多个控件,甚至可以调用this.Refresh()
- 这将更新整个用户控件或窗体拥有您的控件。
但请注意 - 如果您的process
方法运行非常很长时间(例如超过2-3秒) - 您应该考虑在与UI分开的线程中异步执行此操作。它被认为是"良好的风格"因为它不会导致UI冻结。
答案 1 :(得分:2)
您可以使用async
关键字。只有从不同的线程访问UI时,您才必须使用Invoke
private async void button1_Click(object sender, EventArgs e)
{
await Task.Run(
() =>
{
this.Invoke((MethodInvoker)delegate
{
listBox1.Items.Clear();
listBox2.Items.Clear();
listBox3.Items.Clear();
listBox4.Items.Clear();
myLabel.Text = "Getting links...";
});
});
this.process(url);
await Task.Run(
() =>
{
this.Invoke((MethodInvoker)delegate { myLabel.Text = "Finished"; });
});
}
答案 2 :(得分:1)
如何使用Task
在"线程中运行process(url)
"与GUI分开?
通过这种方式,GUI将保持对用户的响应状态"刷新"然后,当您的任务结束时,您只需更新GUI标签。
如果您的操作必须花费一些时间,则应始终将它们与GUI分开。我的两分钱。
答案 3 :(得分:0)
您有2个选项。要么使用其他线程来运行process(url)
,要么在Application.DoEvents()
之前添加。