ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

WPF 调试触发器

2020-12-07 19:01:46  阅读:208  来源: 互联网

标签:触发器 storyboard TriggerBase triggerBase trigger WPF public 调试


翻译自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

标签:触发器,storyboard,TriggerBase,triggerBase,trigger,WPF,public,调试
来源: https://www.cnblogs.com/Lulus/p/14097274.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有