• WPF 调试触发器


    翻译自In WPF, how to debug triggers?
    本来不想发的,但搜索了一下国内好像没人写这个,so.......

    效果如图

    工作原理

    使用附加属性将虚拟动画storyboards添加到触发器
    激活WPF动画跟踪并将结果过滤到仅包含storyboards

    TriggerTracing

    TriggerTracing添加到项目中

    /// <summary>
    /// Contains attached properties to activate Trigger Tracing on the specified Triggers.
    /// 包含附加属性以激活指定触发器上的触发器跟踪
    /// This file alone should be dropped into your app.
    /// 仅此文件应放入您的应用程序
    /// </summary>
    public static class TriggerTracing
    {
        static TriggerTracing()
        {
            // Initialise WPF Animation tracing and add a TriggerTraceListener
            //初始化WPF动画跟踪并添加TriggerTraceListener
            PresentationTraceSources.Refresh();
            PresentationTraceSources.AnimationSource.Listeners.Clear();
            PresentationTraceSources.AnimationSource.Listeners.Add(new TriggerTraceListener());
            PresentationTraceSources.AnimationSource.Switch.Level = SourceLevels.All;
        }
    
        #region TriggerName attached property
    
        /// <summary>
        /// Gets the trigger name for the specified trigger. This will be used
        /// to identify the trigger in the debug output.
        /// 获取指定触发器的触发器名称。 这将用于在调试输出中标识触发器。
        /// </summary>
        /// <param name="trigger">The trigger.</param>
        /// <returns></returns>
        public static string GetTriggerName(TriggerBase trigger)
        {
            return (string)trigger.GetValue(TriggerNameProperty);
        }
    
        /// <summary>
        /// Sets the trigger name for the specified trigger. This will be used
        /// to identify the trigger in the debug output.
        /// 设置指定触发器的触发器名称。 这将用于在调试输出中标识触发器。
        /// </summary>
        /// <param name="trigger">The trigger.</param>
        /// <returns></returns>
        public static void SetTriggerName(TriggerBase trigger, string value)
        {
            trigger.SetValue(TriggerNameProperty, value);
        }
    
        public static readonly DependencyProperty TriggerNameProperty =
            DependencyProperty.RegisterAttached(
            "TriggerName",
            typeof(string),
            typeof(TriggerTracing),
            new UIPropertyMetadata(string.Empty));
    
        #endregion
    
        #region TraceEnabled attached property
    
        /// <summary>
        /// Gets a value indication whether trace is enabled for the specified trigger.
        /// 获取一个值指示是否为指定的触发器启用跟踪
        /// </summary>
        /// <param name="trigger">The trigger.</param>
        /// <returns></returns>
        public static bool GetTraceEnabled(TriggerBase trigger)
        {
            return (bool)trigger.GetValue(TraceEnabledProperty);
        }
    
        /// <summary>
        /// Sets a value specifying whether trace is enabled for the specified trigger
        /// 设置一个值,该值指定是否为指定的触发器启用跟踪
        /// </summary>
        /// <param name="trigger"></param>
        /// <param name="value"></param>
        public static void SetTraceEnabled(TriggerBase trigger, bool value)
        {
            trigger.SetValue(TraceEnabledProperty, value);
        }
    
        public static readonly DependencyProperty TraceEnabledProperty =
            DependencyProperty.RegisterAttached(
            "TraceEnabled",
            typeof(bool),
            typeof(TriggerTracing),
            new UIPropertyMetadata(false, OnTraceEnabledChanged));
    
        private static void OnTraceEnabledChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var triggerBase = d as TriggerBase;
    
            if (triggerBase == null)
                return;
    
            if (!(e.NewValue is bool))
                return;
    
            if ((bool)e.NewValue)
            {
                // insert dummy story-boards which can later be traced using WPF animation tracing
                //添加虚拟storyboards,以后可以使用WPF动画跟踪对其进行跟踪
                var storyboard = new TriggerTraceStoryboard(triggerBase, TriggerTraceStoryboardType.Enter);
                triggerBase.EnterActions.Insert(0, new BeginStoryboard() { Storyboard = storyboard });
    
                storyboard = new TriggerTraceStoryboard(triggerBase, TriggerTraceStoryboardType.Exit);
                triggerBase.ExitActions.Insert(0, new BeginStoryboard() { Storyboard = storyboard });
            }
            else
            {
                // remove the dummy storyboards
                //移除虚拟storyboards
                foreach (TriggerActionCollection actionCollection in new[] { triggerBase.EnterActions, triggerBase.ExitActions })
                {
                    foreach (TriggerAction triggerAction in actionCollection)
                    {
                        BeginStoryboard bsb = triggerAction as BeginStoryboard;
    
                        if (bsb != null && bsb.Storyboard != null && bsb.Storyboard is TriggerTraceStoryboard)
                        {
                            actionCollection.Remove(bsb);
                            break;
                        }
                    }
                }
            }
        }
    
        #endregion
    
        /// <summary>
        /// 触发器跟踪Storyboard类型
        /// </summary>
        private enum TriggerTraceStoryboardType
        {
            //进入
            Enter, 
            //退出
            Exit
        }
    
        /// <summary>
        /// A dummy storyboard for tracing purposes
        /// 用于跟踪的虚拟storyboard
        /// </summary>
        private class TriggerTraceStoryboard : Storyboard
        {
            public TriggerTraceStoryboardType StoryboardType { get; private set; }
            public TriggerBase TriggerBase { get; private set; }
    
            public TriggerTraceStoryboard(TriggerBase triggerBase, TriggerTraceStoryboardType storyboardType)
            {
                TriggerBase = triggerBase;
                StoryboardType = storyboardType;
            }
        }
    
        /// <summary>
        /// A custom tracelistener.
        /// 自定义跟踪侦听器
        /// </summary>
        private class TriggerTraceListener : TraceListener
        {
            public override void TraceEvent(TraceEventCache eventCache, string source, TraceEventType eventType, int id, string format, params object[] args)
            {
                base.TraceEvent(eventCache, source, eventType, id, format, args);
    
                if (format.StartsWith("Storyboard has begun;"))
                {
                    TriggerTraceStoryboard storyboard = args[1] as TriggerTraceStoryboard;
                    if (storyboard != null)
                    {
                        // add a breakpoint here to see when your trigger has been
                        // entered or exited
                        //在此处添加断点,以查看何时输入或退出触发器
    
                        // the element being acted upon
                        //被作用的元素
                        object targetElement = args[5];
    
                        // the namescope of the element being acted upon
                        //所作用元素的名称范围
                        INameScope namescope = (INameScope)args[7];
    
                        TriggerBase triggerBase = storyboard.TriggerBase;
                        //获得TriggerTracing.TriggerName
                        string triggerName = GetTriggerName(storyboard.TriggerBase);
    
                        Debug.WriteLine(string.Format("Element: {0}, {1}: {2}: {3}",
                            targetElement,
                            triggerBase.GetType().Name,
                            triggerName,
                            storyboard.StoryboardType));
                    }
                }
            }
    
            public override void Write(string message)
            {
            }
    
            public override void WriteLine(string message)
            {
            }
        }
    }
    

    使用

    将以下附加属性添加到任何触发器,将在输出窗口中看到它何时被激活/停用

    TriggerTracing.TriggerName="your debug name"
    TriggerTracing.TraceEnabled="True"
    

    例子

    <Trigger my:TriggerTracing.TriggerName="BoldWhenMouseIsOver"  
            my:TriggerTracing.TraceEnabled="True"  
            Property="IsMouseOver"  
            Value="True">  
        <Setter Property = "FontWeight" Value="Bold"/>  
    </Trigger> 
    

    示例代码

    DebugTriggers

  • 相关阅读:
    C# linq根据属性分组,并累加计算
    AR模板分组显示(C#打印)
    显示单据信息(类似打印)
    C#同步方法中调用异步方法
    win10 Git安装或者使用出现128问题
    简单的分页查询实现
    数据库批量插入【数据库】
    VideoView
    音乐播放
    画画板案例
  • 原文地址:https://www.cnblogs.com/Lulus/p/14097274.html
Copyright © 2020-2023  润新知