WPF C#锁定/解锁按钮并执行一个线程

时间:2013-11-04 10:44:15

标签: c# wpf multithreading button

有人可以帮我理解为什么这段代码不起作用吗?

我想要做的是:点击按钮,更改按钮内容并将其锁定,执行外部线程,最后解锁按钮并再次更改内容

private void button3_Click(object sender, RoutedEventArgs e)
{
    button3.Content = "Printing...";
    button3.IsEnabled = false;

    Thread.Sleep(1000);

    button3.IsEnabled = true;
    button3.Content = "Print";
}

4 个答案:

答案 0 :(得分:2)

您看到此行为的原因是因为您的方法(处理按钮的Click事件)与UI在同一个线程上运行。在使用UI代码时,这个概念是常见的问题来源。

简单地说,在方法完成之前,无法重新绘制UI。在该方法中,您禁用按钮,等待1秒钟,然后重新启用按钮 - 然后然后重新绘制UI,并启用按钮。出于这个原因,您永远不会在屏幕上看到该按钮被禁用(并且您的应用程序将在Sleep发生时冻结1秒钟。)

您需要做的是调查可用于在后台线程上运行任务的方法之一。您的方法应该创建并启动此线程,将按钮设置为禁用,然后完成 - 允许UI线程将按钮绘制为禁用。当您的任务完成后,您应该将按钮设置为再次启用(请注意,通常在WPF中这将意味着使用Dispatcher.Invoke来确保从UI线程设置button.Enabled

要创建后台任务,您可以查看System.Threading名称空间(特别是Thread.Start方法),Task Parallel LibraryBackgroundWorker类。我怀疑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 synchronouslyforce 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.

希望这会有所帮助 谢谢。