InvalidOperationException: 调度程序处理已暂停,但仍在处理消息。

5
我们遇到了多个与此异常相关的问题,但我找不到有关该问题真正原因的技术文档,也没有找到所有可能导致此错误的信息来源以及我们应该避免什么才能避免出现这个异常。
我已经阅读了以下内容:
“调度处理被暂停以避免在更新可视树时产生重入问题。”
但我不确定“更新可视树”的含义,以及是什么导致消息发送到分派程序并导致该问题再次发生。
以下示例代码会重现此问题:
XAML
<Window x:Class="SuspendedPOF.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" 
        Height="350" 
        Width="525">
    <StackPanel>
        <Button Content="1" x:Name="Button1"  IsVisibleChanged="Button1_OnIsVisibleChanged" />
    </StackPanel>
</Window>

C# 代码

using System.Windows;

namespace SuspendedPOF
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        private void Button1_OnIsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
        {
            MessageBox.Show("Hello");
        }
    }
}

MessageBox调用不是唯一可能触发这个异常的方法,类似于Focus等其他操作也有可能出现问题。

任何帮助将不胜感激。

2个回答

5
重点在于,在处理按钮的可见性改变时,您可能正在尝试更改其视觉状态。这可能会导致无限循环(就像您所读的「重入问题」一样),这也是您得到 InvalidOperationException 的原因。
为避免此问题,您需要通过使用 Dispatcher 推迟打开 MessageBox。然后在 Button1_OnIsVisibleChanged 方法中,使用以下代码:
Dispatcher.BeginInvoke(new Action(() => System.Windows.MessageBox.Show("Hello")),
    System.Windows.Threading.DispatcherPriority.Normal);

不要直接调用 MessageBoxShow 静态方法。


好的,但是在开发时我怎么知道事件处理程序是有问题的之一,并且事件处理程序内部的方法可能会修改按钮的视觉状态?消息框似乎不会修改按钮的视觉状态。 - Ignacio Soler Garcia
@IgnacioSolerGarcia 我认为你(或你的同事)应该问问自己,处理控件的“IsVisibleChanged”事件的代码是否试图改变同一控件的可视状态。我猜没有其他方法。例如,显示消息框可能会潜在地隐藏您的控件(考虑消息框是否出现在其上方)。在这种情况下,您必须使用“Dispatcher”,否则您不需要。 - Il Vic
说实话,这听起来很疯狂。没有考虑使用BeginInvoke启动事物会使它们变得不同步,因此流程在执行之间可能会有所不同... - Ignacio Soler Garcia
不,我的意思是首先要知道处理事件的代码是否最终在可能很大的调用树中修改了可视树的某些内容,其次要知道哪些事件管理每个控件的可视状态(包括第三方控件,如Telerik或DevExpress)。 - Ignacio Soler Garcia
而且这与操作系统有关。该应用程序在Win7上运行得更或多或少还可以,但在W8.1或W10上,异常情况更经常发生,不确定原因是什么。 - Ignacio Soler Garcia
显示剩余2条评论

0
据我所知,没有办法知道您处理的事件是否会修改控件的视觉状态,也无法知道您的操作是否会修改 UI 的视觉状态,所以只需在发现崩溃时进行 BeingInvokes 处理就行了…… :S

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接