使用WPF,是否有一种方法可以检测阻塞GUI更新的方法调用?

3

我想知道是否有一种技术或方法可以检测WPF应用程序中未使用async/await的调用。

我提出这个问题是因为我正在处理的WPF应用程序在屏幕更新时会出现卡顿和停顿,而我似乎无法追踪阻塞GUI线程的调用源。

我正在使用MVVM设计模式的VS2012和VS2013。


有关WPF Dispatcher线程工作原理的更多信息,请参见http://weblogs.asp.net/pawanmishra/understanding-dispatcher-in-wpf。 - Contango
4个回答

8

虽然这不是直接回答你的问题,但以下代码可以用于识别调度程序线程何时超负荷。该代码使用围绕DispatcherInactive事件的事件处理程序来计算调度程序线程已被阻塞(超载)多长时间:

var maxThreshold = TimeSpan.FromMilliseconds(750);
var previous = DateTime.Now;

     Application.Current.MainWindow
        .Dispatcher.Hooks.DispatcherInactive += (sender, eventArgs) =>
        {
            var current = DateTime.Now;
            var delta = current - previous;

            previous = current;

            if (delta > maxThreshold)
            {
                Debug.WriteLine("UI Freeze = {0} ms", delta.TotalMilliseconds);
            }
         };

我建议只在调试模式下使用此功能,因此它应该包含在#if DEBUG块中。你不希望它在生产环境中运行。

这段代码绝对是精华。将其添加到您的代码中,在“Debug”行上设置断点,如果GUI线程被阻塞时间过长,它将立即中断。我希望我有更多的投票支持这个答案。 - Contango

1
你可以订阅WPF调度程序的事件以追踪问题。UI线程将工作项排队到称为调度程序的对象中。调度程序按优先级选择工作项并运行每个工作项直至完成。
要监视调度程序,您可以例如订阅这些操作:
Dispatcher.Hooks.OperationPosted += Hooks_OperationPosted;
Dispatcher.Hooks.OperationStarted += Hooks_OperationStarted;
Dispatcher.Hooks.OperationAborted += Hooks_OperationAborted;

你可以在这里找到完整列表。
根据你的问题,你可能会发现使用商业分析工具更好,但通常只需观察调度队列即可获得良好结果。

有关更多信息,请参见https://dev59.com/WG3Xa4cB1Zd3GeqPaQxb - Contango
示例代码,请参见http://braaagh-ux.blogspot.co.uk/2011/05/wpf-dispatcher-monitoring-activity.html。 - Contango

1

我认为性能分析器可以帮助您解决这个问题。 我个人推荐ANTS性能分析器,您可以下载试用版并测试您的应用程序。它可以告诉您应用程序的某个执行期间花费了多少时间。


1
通常很容易找到阻塞用户界面(UI)的原因。有两种情况 - 要么您在UI线程上执行一个昂贵的操作,您可以使用以下代码测试正在执行的线程是否是UI线程:
if (Thread.CurrentThread == Dispatcher.CurrentDispatcher.Thread)
{
    //UI Thread
}

或者,您显示了太多控件,导致渲染时间过长。通常情况下,当列表不对项目进行虚拟化时,会出现这种情况。

+1 表示列表必须虚拟化项目。这对于性能改进非常重要。 - Contango

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