2012-03-07 74 views
9

調試WPF事件或綁定時使用什麼方法?調試WPF事件,綁定

我試圖使用斷點,但它似乎是我的XAML或代碼後面,它從來沒有擊中斷點的錯誤。

有沒有辦法看到當我點擊WPF中的某些東西,什麼事件消息彈出或不彈出來明白出了什麼問題?

回答

23

在過去3年建設WPF應用我已經收集到的各種反應預防性解決方案,以確保一切結合在一起,幾乎正常專職的。

注意: 我會給你一個快速總結,然後在早上(10小時內)回覆代碼示例/截圖。

這是我的最有效的工具:

1)創建執行ConvertConvertBack時打破了調試器的轉換器。一種快速而有用的方式來確保您擁有您期望的價值。我第一次從Bea Stollnitz's blog post得知這個技巧。

DebugConverter.cs

public class DebugConverter : IValueConverter 
{ 

    public object Convert(object value, Type targetType, object parameter, CultureInfo culture) 
    { 
     if (Debugger.IsAttached) 
      Debugger.Break(); 

     return Binding.DoNothing; 
    } 

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) 
    { 
     if (Debugger.IsAttached) 
      Debugger.Break(); 

     return Binding.DoNothing; 
    } 

} 

2)創建TraceListener截取的任何錯誤。這與您在連接調試器時在Visual Studio輸出窗口中看到的類似。使用這種方法,當綁定操作期間拋出異常時,我可以讓調試器中斷。這比設置PresentationTraceSources.TraceLevel好,因爲它適用於整個應用程序,而不是每個綁定。

DataBindingErrorLogger。CS

public class DataBindingErrorLogger : DefaultTraceListener, IDisposable 
{ 
    private ILogger Logger; 

    public DataBindingErrorLogger(ILogger logger, SourceLevels level) 
    { 
     Logger = logger; 

     PresentationTraceSources.Refresh(); 
     PresentationTraceSources.DataBindingSource.Listeners.Add(this); 
     PresentationTraceSources.DataBindingSource.Switch.Level = level; 
    } 

    public override void Write(string message) 
    { 
    } 

    public override void WriteLine(string message) 
    { 
     Logger.BindingError(message); 

     if (Debugger.IsAttached && message.Contains("Exception")) 
      Debugger.Break(); 
    } 

    protected override void Dispose(bool disposing) 
    { 
     Flush(); 
     Close(); 

     PresentationTraceSources.DataBindingSource.Listeners.Remove(this); 
    } 

} 

用法

DataBindingErrorLogger = new DataBindingErrorLogger(Logger, SourceLevels.Warning); 

在上文中,​​是NLog日誌寫入器。我有一個更復雜的DefaultTraceListener版本,它可以報告完整的堆棧跟蹤,並且實際上會拋出異常,但是這將足以讓您開始使用(如果您想自己實現,那麼Jason Bock有article on this extended implementation,儘管您需要代碼才能實際執行讓它工作)。

3)使用Snoop WPF自檢工具深入您的視圖並檢查您的數據對象。使用Snoop,您可以查看視圖的邏輯結構並以交互方式更改值以測試不同的條件。

Snoop WPF

史努比WPF是絕對必要任何WPF應用程序的迭代時間。在其衆多功能中,Delve命令允許您深入查看/查看模型並交互式地調整值。要深入查看屬性,請右鍵單擊以打開上下文菜單並選擇Delve命令;要恢復一個級別(未研究?),在右上角有一個小按鈕^。例如,嘗試深入研究DataContext屬性。

編輯:我不能相信我只注意到這一點,但沒有在窺探WPF窗口數據上下文標籤。在#DEBUGINotifyPropertyChanged事件

DataContext Tab

4)運行時檢查。由於數據綁定系統依賴於在屬性發生變化時收到通知,因此您的理智很重要,即您正在通知正確的屬性已更改。有了一些反思魔法,你可以在出現問題時用Debug.Assert

PropertyChangedHelper.cs

public static class PropertyChangedHelper 
{ 
    #if DEBUG 
    public static Dictionary<Type, Dictionary<string, bool>> PropertyCache = new Dictionary<Type, Dictionary<string, bool>>(); 
    #endif 

    [DebuggerStepThrough] 
    public static void Notify(this INotifyPropertyChanged sender, PropertyChangedEventHandler eventHandler, string propertyName) 
    { 
     sender.Notify(eventHandler, new PropertyChangedEventArgs(propertyName), true); 
    } 

    [DebuggerStepThrough] 
    public static void Notify(this INotifyPropertyChanged sender, PropertyChangedEventHandler eventHandler, string propertyName, bool validatePropertyName) 
    { 
     sender.Notify(eventHandler, new PropertyChangedEventArgs(propertyName), validatePropertyName); 
    } 

    [DebuggerStepThrough] 
    public static void Notify(this INotifyPropertyChanged sender, PropertyChangedEventHandler eventHandler, PropertyChangedEventArgs eventArgs) 
    { 
     sender.Notify(eventHandler, eventArgs, true); 
    } 

    [DebuggerStepThrough] 
    public static void Notify(this INotifyPropertyChanged sender, PropertyChangedEventHandler eventHandler, PropertyChangedEventArgs eventArgs, bool validatePropertyName) 
    { 
     #if DEBUG 
     if (validatePropertyName) 
      Debug.Assert(PropertyExists(sender as object, eventArgs.PropertyName), String.Format("Property: {0} does not exist on type: {1}", eventArgs.PropertyName, sender.GetType().ToString())); 
     #endif 

     // as the event handlers is a parameter is actually somewhat "thread safe" 
     // http://blogs.msdn.com/b/ericlippert/archive/2009/04/29/events-and-races.aspx 
     if (eventHandler != null) 
      eventHandler(sender, eventArgs); 
    } 

    #if DEBUG 
    [DebuggerStepThrough] 
    public static bool PropertyExists(object sender, string propertyName) 
    { 
     // we do not check validity of dynamic classes. it is possible, however since they're dynamic we couldn't cache them anyway. 
     if (sender is ICustomTypeDescriptor) 
      return true; 

     var senderType = sender.GetType();  
     if (!PropertyCache.ContainsKey(senderType)) 
      PropertyCache.Add(senderType, new Dictionary<string,bool>()); 

     lock (PropertyCache) 
     { 
      if (!(PropertyCache[senderType].ContainsKey(propertyName))) 
      { 
       var hasPropertyByName = (senderType.GetProperty(propertyName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static) != null); 
       PropertyCache[senderType].Add(propertyName, hasPropertyByName); 
      } 
     } 

     return PropertyCache[senderType][propertyName]; 
    } 
    #endif 

} 

HTH,

+0

任何問題,給我留言。 – Dennis 2012-03-08 10:05:24

1

您是否已將視圖輸出激活。這將顯示一些綁定錯誤。 PresentationTraceSources.TraceLevel =「高」將顯示更多信息。它在到達斷點之前可能會發生錯誤。在構造函數中設置一個斷點,以查看其工作。

1

在綁定中添加「pass-through」轉換器有時可以幫助您在轉換器中放置一個斷點,以便在有綁定更新時將其拉出。它還允許您通過Convert和ConvertBack值參數的綁定來查看值傳遞的方式。

public class PassthroughConverter : IValueConverter { 
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { 
     return value; // Breakpoint here. 
    } 
    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { 
     return value; // Breakpoint here. 
    } 
} 

如果可以訪問由名稱對照然後在Window.xaml.cs您可以使用檢查控制綁定的狀態:

BindingExpression be = comboMyCombo.GetBindingExpression(ComboBox.IsEnabledProperty); 

看着「是」在調試器可以提供幫助(有時綁定會在某些操作中被重置/中斷)。