• WPF 如何知道当前有多少个 DispatcherTime 在运行


    在 WPF 调试中,对于 DispatcherTimer 定时器的执行,没有直观的调试方法。本文来告诉大家如何在 WPF 中调试当前主线程有多少个 DispatcherTimer 在运行

    在 WPF 中,如果有 DispatcherTimer 定时器在执行,将会影响到主线程的执行,将会让主线程诡异忙碌。或者有 DispatcherTimer 定时器忘记订阅 Tick 同时也忘记设置时间,将会不断消耗主线程资源。在遇到没有任何的交互时,此时出现的主线程卡的问题,可以优先尝试了解是否 DispatcherTime 定时器的问题

    如以下代码,在界面创建一个按钮,点击按钮时将会创建和运行 DispatcherTime 定时器

      <Grid>
        <Button Margin="10,10,10,10" HorizontalAlignment="Left" VerticalAlignment="Top" Content="按钮" Click="Button_OnClick" />
      </Grid>
    

    Button_OnClick 加上创建和运行 DispatcherTimer 定时器的代码

            private void Button_OnClick(object sender, RoutedEventArgs e)
            {
                var dispatcherTimer = new DispatcherTimer()
                {
                    Interval = TimeSpan.FromSeconds(1)
                };
                dispatcherTimer.Start();
            }
    

    假定需要调试在进入 Button_OnClick 方法,当前主线程有多少 DispatcherTimer 定时器在运行。可以在此方法上添加断点,如下图

    进入 VisualStudio 的监视界面,输入 System.Windows.Threading.Dispatcher.CurrentDispatcher._timers 即可了解当前主线程有多少个 DispatcherTime 定时器在运行。根据 Dispatcher.CurrentDispatcher 的定义,此 CurrentDispatcher 是 ThreadStatic 线程静态,因此以上调试断点必须落在主线程执行的代码

    如进一步了解当前的 DispatcherTimer 定时器是由哪个业务模块定义的,可以通过 Tick 委托找到对应的业务模块,如下图

    通过 Tick 委托可以了解到是哪个类的哪个方法,通过静态代码可以找到业务

    如果只是期望调试 DispatcherTimer 定时器是由哪个业务模块启动创建的,此时可以添加函数断点,添加函数断点步骤相对复杂

    在开始之前,需要加载 WindowsBase.dll 的符号,同时我也推荐使用 dotnet core 或 .NET 5 版本的 WPF 框架进行调试,因此此框架可以有源代码支持。加载 WindowsBase.dll 的符号之前,还请到开源的 WPF 项目,将代码拉到本地

    加载 WindowsBase.dll 的符号方法是在 调试->窗口->模块 打开模块窗口,右击 WindowsBase.dll 加载符号

    加载符号时需要一点网络,基本上都能加载成功。为什么需要加载 WindowsBase.dll 的符号?原因是 System.Windows.Threading.DispatcherTimer 定义在 WindowsBase 程序集

    接下来在断点窗口里面,点击新建函数断点

    输入调试的函数,进行断点,如断点放在 System.Windows.Threading.DispatcherTimer.Start 函数里面,当然,这只是一个例子

    这样在触发 DispatcherTimer.Start 函数将会进入断点

    断点进入之后,默认都会提示是否选择源代码,这就是上文推荐使用开源版本的 WPF 框架的原因,因为咱可以找到此文件进行加载,这样就能实现源代码级的调试。如果发现源代码有一些不匹配,也莫慌,将自己的代码仓库切换到对应的分支或 tag 即可,或者去掉勾选源代码必须匹配选项

    通过调用堆栈即可了解到当前是哪个模块调用了 DispatcherTimer.Start 函数

    以上步骤比较多,还需要大家玩一下才能了解

    其实 DispatcherTimer.Start 函数将会在框架内部消息里面不断调用,因此断点不建议落在 Start 函数,按照咱的调试需求,其实更多的是在构造函数,可以在函数断点里面输入 System.Windows.Threading.DispatcherTimer.DispatcherTimer 调试是哪个业务创建 DispatcherTimer 对象

    本文所有代码放在 githubgitee 欢迎小伙伴访问

    更多代码调试请看 dotnet 代码调试方法

    博客园博客只做备份,博客发布就不再更新,如果想看最新博客,请到 https://blog.lindexi.com/

    知识共享许可协议
    本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。欢迎转载、使用、重新发布,但务必保留文章署名[林德熙](http://blog.csdn.net/lindexi_gd)(包含链接:http://blog.csdn.net/lindexi_gd ),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。如有任何疑问,请与我[联系](mailto:lindexi_gd@163.com)。
  • 相关阅读:
    IPhone手机页面中点击文本输入框,弹出键盘,网页会放大,如何解决
    JQuery让input从disabled变成enabled
    c# winform 获取当前程序运行根目录,winform 打开程序运行的文件夹
    如何让Snippet Compiler 2008 支持linq
    org.in2bits.MyXls.XlsDocument 生成excel文件 ; 如果想读取模板再另外生成的话,试试 NPOI
    Vue学习笔记八:v-for,v-if,v-show指令
    Vue学习笔记七:Vue中的样式
    Vue学习笔记六:v-model 数据双向绑定
    Vue学习笔记五:事件修饰符
    Vue学习笔记四:跑马灯效果
  • 原文地址:https://www.cnblogs.com/lindexi/p/14743481.html
Copyright © 2020-2023  润新知