Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/272.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/user-interface/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
WPF C#锁定/解锁按钮并执行线程_C#_Wpf_Multithreading_Button - Fatal编程技术网

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

WPF C#锁定/解锁按钮并执行线程,c#,wpf,multithreading,button,C#,Wpf,Multithreading,Button,有人能帮我理解为什么这段代码不起作用吗 我想做的是:单击按钮,更改按钮内容并锁定它,执行外部线程,最后解锁按钮并再次更改内容 private void button3_Click(object sender, RoutedEventArgs e) { button3.Content = "Printing..."; button3.IsEnabled = false; Thread.Sleep(1000); button3.IsEnabled = true;

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

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

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

    Thread.Sleep(1000);

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

单击按钮时将禁用该按钮,但不会再次启用。你能做的是

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.
希望这有帮助
谢谢

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

简单地说,在方法完成之前无法重新绘制UI。在禁用按钮的方法中,等待1秒,然后重新启用按钮,然后重新绘制UI,并启用按钮。因此,您永远不会在屏幕上看到按钮被禁用(当
睡眠时,您的应用程序将冻结1秒)

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


要创建后台任务,您可以查看
System.Threading
名称空间(特别是方法),或,或类。我怀疑TPL将是您最容易的出发点。

您正睡在UI线程上
这会冻结您的UI线程,因此您不会看到UI上的任何更新

控件的重画由UI调度程序完成,但调度程序执行 基于为任务设置的优先级的操作。重画 对设置为渲染的调度程序优先级执行控制。背景 按钮的内容以优先级呈现在调度程序上排队,但 只有在获得所有具有较高优先级的任务后,才会获得执行 完成

正如其他人所建议的,您应该将长时间运行的任务移动到单独的线程上,但在UI线程上睡觉之前,还有另一种方法可以刷新GUI。正如我提到的,一旦所有高于
DispatcherPriority.Render的任务完成,UI将被重新绘制。因此,您可以做的是,在线程睡眠之前,
将一个具有渲染优先级的空委托同步排队
,这将
强制调度程序执行上述所有任务,并在移动到下一个任务之前,使用优先级渲染
。这就是我的意思-

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";
}
在UI线程上睡觉之前,只需调用
按钮3.Refresh()

但是,这也有一个缺点,因为它不仅会刷新你的按钮3 但由于dispatcher将完成所有其他控件,所以所有其他控件都将在UI上等待刷新 优先级为或更高的任务在移动到下一个任务之前渲染


但请记住,永远不要在UI线程上休眠。使处理程序异步可以解决问题:

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";
}

已知问题。您需要使用dispatcher使用户界面与内容同步。@daveL,按钮没有文本属性调用线程。在UI事件处理程序中睡眠会阻止UI线程。在StackOverflow中搜索“UI冻结”或“阻止UI线程”或类似内容,以获得大量答案。@user2941172-您可以在线程上睡眠之前,通过调用调度程序上的空委托(优先级设置为
Render
),刷新GUI。在我的回答中添加了更多细节,说明了使用这种方法的缺点。作为一个简单的经验法则,你不应该调用线程。在UI线程中睡眠。在发布的代码中的“button3.IsEnabled=true;”一行可能表明你的答案不正确……是的,你是对的,但我只提到了另一种方法。就是这样,大部分都是对的。但是这一行-
在方法完成之前无法重新绘制UI
不总是正确的。若我在UI dispatcher上将优先级为
Render
的任务排队,那个么UI将在方法完成之前刷新。请查看我答案中的详细信息。从技术上讲,这是可行的,但它是通过让位于调度程序队列中优先级高于
Render
的所有其他内容来实现的。这是一个相当不确定的大锤来敲开一个螺母-而且它也不是最明显或可读的代码。你说得对,几乎总是有办法改变通常的行为,但我从不主张这样做。如果我在代码评审中看到这段代码,我会拒绝它。@Dan-这也是我也不鼓励的,这就是为什么我最后提到使用这种方法的缺点。我同意你在回答中提到的所有内容,因为这是刷新UI的方法之一(绝对不鼓励):)
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";
}