2012-03-07 72 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); 

看着“是”在调试器可以提供帮助(有时绑定会在某些操作中被重置/中断)。