调试WPF事件或绑定时使用什么方法?调试WPF事件,绑定
我试图使用断点,但它似乎是我的XAML或代码后面,它从来没有击中断点的错误。
有没有办法看到当我点击WPF中的某些东西,什么事件消息弹出或不弹出来明白出了什么问题?
调试WPF事件或绑定时使用什么方法?调试WPF事件,绑定
我试图使用断点,但它似乎是我的XAML或代码后面,它从来没有击中断点的错误。
有没有办法看到当我点击WPF中的某些东西,什么事件消息弹出或不弹出来明白出了什么问题?
在过去3年建设WPF应用我已经收集到的各种反应和预防性解决方案,以确保一切结合在一起,几乎正常专职的。
注意:
我会给你一个快速总结,然后在早上(10小时内)回复代码示例/截图。
这是我的最有效的工具:
1)创建执行Convert
和ConvertBack
时打破了调试器的转换器。一种快速而有用的方式来确保您拥有您期望的价值。我第一次从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,您可以查看视图的逻辑结构并以交互方式更改值以测试不同的条件。
史努比WPF是绝对必要任何WPF应用程序的迭代时间。在其众多功能中,Delve命令允许您深入查看/查看模型并交互式地调整值。要深入查看属性,请右键单击以打开上下文菜单并选择Delve命令;要恢复一个级别(未研究?),在右上角有一个小按钮^。例如,尝试深入研究DataContext
属性。
编辑:我不能相信我只注意到这一点,但没有在窥探WPF窗口数据上下文标签。在#DEBUG
INotifyPropertyChanged
事件
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,
您是否已将视图输出激活。这将显示一些绑定错误。 PresentationTraceSources.TraceLevel =“高”将显示更多信息。它在到达断点之前可能会发生错误。在构造函数中设置一个断点,以查看其工作。
在绑定中添加“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);
看着“是”在调试器可以提供帮助(有时绑定会在某些操作中被重置/中断)。
任何问题,给我留言。 – Dennis 2012-03-08 10:05:24