有人可以帮我理解为什么这段代码不起作用吗?
我想要做的是:点击按钮,更改按钮内容并将其锁定,执行外部线程,最后解锁按钮并再次更改内容
private void button3_Click(object sender, RoutedEventArgs e)
{
button3.Content = "Printing...";
button3.IsEnabled = false;
Thread.Sleep(1000);
button3.IsEnabled = true;
button3.Content = "Print";
}
答案 0 :(得分:2)
您看到此行为的原因是因为您的方法(处理按钮的Click
事件)与UI在同一个线程上运行。在使用UI代码时,这个概念是常见的问题来源。
简单地说,在方法完成之前,无法重新绘制UI。在该方法中,您禁用按钮,等待1秒钟,然后重新启用按钮 - 然后然后重新绘制UI,并启用按钮。出于这个原因,您永远不会在屏幕上看到该按钮被禁用(并且您的应用程序将在Sleep
发生时冻结1秒钟。)
您需要做的是调查可用于在后台线程上运行任务的方法之一。您的方法应该创建并启动此线程,将按钮设置为禁用,然后完成 - 允许UI线程将按钮绘制为禁用。当您的任务完成后,您应该将按钮设置为再次启用(请注意,通常在WPF中这将意味着使用Dispatcher.Invoke
来确保从UI线程设置button.Enabled
。
要创建后台任务,您可以查看System.Threading
名称空间(特别是Thread.Start
方法),Task Parallel Library或BackgroundWorker类。我怀疑TPL将是你最简单的起点。
答案 1 :(得分:2)
您sleeping on UI thread
冻结了您的UI线程,因此您没有在UI上看到任何更新。
重新绘制控件由UI调度程序完成,但调度程序执行 基于为任务设置的优先级的操作。重绘 控件在调度程序优先级设置为Render时完成。设置 按钮的内容在调度程序上排队,但优先级为渲染 只有具有更高优先级的所有任务获得后才会执行 完成。
正如其他人建议你应该在单独的线程上移动长时间运行的任务,但是在睡眠UI线程之前还有另一个工作区来刷新GUI。就像我提到的,一旦所有高于DispatcherPriority.Render
的任务完成,UI将被重绘。因此,您可以做的是before sleeping on thread enqueue an empty delegate with render priority synchronously
,force dispatcher to perform all tasks above and with priority render
在转到下一个任务之前private void button3_Click(object sender, RoutedEventArgs e)
{
button3.Content = "Printing...";
button3.IsEnabled = false;
Dispatcher.Invoke((Action)(() => { }), DispatcherPriority.Render); <-- HERE
// button3.Refresh(); <-- After having extension method on UIElement.
Thread.Sleep(1000);
button3.IsEnabled = true;
button3.Content = "Print";
}
。这就是我的意思 -
public static void Refresh(this UIElement uiElement)
{
uiElement.Dispatcher.Invoke((Action)(() => { }), DispatcherPriority.Render);
}
此外,您可以将此方法作为UIElement上的扩展方法 -
button3.Refresh()
在睡眠UI线程之前调用{{1}}。
但是,这也有一个缺点,因为它不仅会刷新你的button3 但所有其他控件都在UI上等待刷新,因为调度程序将完成所有操作 在转移到下一个任务之前,优先级渲染或更高的任务。
但请始终牢记,永远不要在UI线程上睡觉。
答案 2 :(得分:0)
使处理程序异步处理问题:
private async void button3_Click(object sender, RoutedEventArgs e)
{
button3.Content = "Printing...";
button3.IsEnabled = false;
await Task.Delay(1000);
button3.IsEnabled = true;
button3.Content = "Print";
}
答案 3 :(得分:-2)
您在单击按钮时禁用该按钮但未再次启用该按钮。你能做什么,
1. initiate a timer
when button is clicked then,
1. change content, disable the button
2. start the timer
3. after a certain duration when the external thread is executed enable the button again and change it's content.
希望这会有所帮助 谢谢。