C語言的觀察者模式(鳳姐與粉絲)
阿新 • • 發佈:2020-12-07
技術標籤: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>