WPF debug:
一.Output window 输出:
<Image Source="{Binding Path=Full}"/>
System.Windows.Data Error: 35 : BindingExpression path error: 'Full' property not found on 'object' ''FileInfo' (HashCode=26218178)'. BindingExpression:Path=Full; DataItem='FileInfo' (HashCode=26218178); target element is 'Image' (Name=''); target property is 'Source' (type 'ImageSource')
Disadvantage: The output window will print so much information that it may be hard to find the error you’re looking for.
二 . 使用 WPF Tracing:
We know the .net tracing: The .Net platform provides some classes to allow you to send trace messages, not only to the debug output window, but to a file, or anyone else that wants to listen. You can send traces using the static System.Diagnostics.Trace class in .Net 1.0 and in .Net 2.0 using TraceSource objects.
Please see http://msdn.microsoft.com/en-us/library/system.diagnostics.tracesource.aspx for detail.
Instead, we focus ourselves on the WPF tracing (.Config file):
1. Get the trace sources enabled first.
增加注册表项:To enable WPF tracing in the registry, create the key
"hkey_current_user"software"microsoft"tracing"wpf", add a "ManagedTracing" DWORD value, and set it to one.
另外,当程序从debugger中启动时,有些wpf tracing是自动注册的,比如data binding,这样直接可以output window看到:
Additionally, some WPF tracing is enabled automatically when you launch your app from within the debugger. Specifically, this is the case for databinding warnings and errors.
开始写配置文件, app.config:
<configuration>
<system.diagnostics>
<sources>
<!--
<source name="System.Windows.Data" switchName="SourceSwitch" >
<listeners>
<add name="textListener" />
</listeners>
</source>
-->
<!--
<source name="System.Windows.DependencyProperty" switchName="SourceSwitch" >
<listeners>
<add name="textListener" />
</listeners>
</source>
-->
<!--
<source name="System.Windows.Freezable" switchName="SourceSwitch" >
<listeners>
<add name="textListener" />
</listeners>
</source>
-->
<!--
<source name="System.Windows.RoutedEvent" switchName="SourceSwitch" >
<listeners>
<add name="textListener" />
</listeners>
</source>
-->
<!--
<source name="System.Windows.Media.Animation" switchName="SourceSwitch" >
<listeners>
<add name="textListener" />
</listeners>
</source>
-->
<!--
<source name="System.Windows.NameScope" switchName="SourceSwitch" >
<listeners>
<add name="textListener" />
</listeners>
</source>
-->
<!--
<source name="System.Windows.ResourceDictionary" switchName="SourceSwitch" >
<listeners>
<add name="textListener" />
</listeners>
</source>
-->
<!--
<source name="System.Windows.Markup" switchName="SourceSwitch" >
<listeners>
<add name="textListener" />
</listeners>
</source>
-->
<!--
<source name="System.Windows.Documents" switchName="SourceSwitch" >
<listeners>
<add name="textListener" />
</listeners>
</source>
-->
</sources>
<switches>
<add name="SourceSwitch" value="All" />
<!--add name="SourceSwitch" value="Off" -->
<!--add name="SourceSwitch" value="Verbose" -->
<!--add name="SourceSwitch" value="Warning" -->
<!--add name="SourceSwitch" value="Activity" -->
</switches>
<sharedListeners>
<!-- This listener sends output to the console -->
<add name="console"
type="System.Diagnostics.ConsoleTraceListener"
initializeData="false"/>
<!-- This listener sends output to an Xml file named AvTrace.xml -->
<add name="xmlListener"
type="System.Diagnostics.XmlWriterTraceListener"
traceOutputOptions="None"
initializeData="AvTrace.xml" />
<!-- This listener sends output to a file named AvTrace.txt -->
<add name="textListener"
type="System.Diagnostics.TextWriterTraceListener"
initializeData="AvTrace.txt" />
</sharedListeners>
<trace autoflush="true" indentsize="4"></trace>
</system.diagnostics>
</configuration>
Source tag, 指出你是需要探测那个命名空间的信息(only the message generated in System.Windows.Markup namespace). Data binding 在System.windows.Data空间下。
<source name="System.Windows.Markup" switchName="SourceSwitch" >
<listeners>
<add name="textListener" />
</listeners>
</source>
Swithes tag, 指出需要的message档次, 需要所有的信息则value=”All”, 还可以是off,Verbose,Warning,Activity等,详见SourceLevel in .net reflector.
<switches>
<add name="SourceSwitch" value="All" />
<!--add name="SourceSwitch" value="Off" -->
<!--add name="SourceSwitch" value="Verbose" -->
<!--add name="SourceSwitch" value="Warning" -->
<!--add name="SourceSwitch" value="Activity" -->
</switches>
trace level, 即value
Off | Output no tracing and debugging messages. | |
Error | Output error-handling messages. | |
Warning | Output warnings and error-handling messages. | |
Info | Output informational messages, warnings, and error-handling messages. | |
Verbose | Output all debugging and tracing messages. |
sharedListeners tag, 指定输出方式:
<sharedListeners>
<!-- This listener sends output to the console -->
<add name="console"
type="System.Diagnostics.ConsoleTraceListener"
initializeData="false"/>
<!-- This listener sends output to an Xml file named AvTrace.xml -->
<add name="xmlListener"
type="System.Diagnostics.XmlWriterTraceListener"
traceOutputOptions="None"
initializeData="AvTrace.xml" />
<!-- This listener sends output to a file named AvTrace.txt -->
<add name="textListener"
type="System.Diagnostics.TextWriterTraceListener"
initializeData="AvTrace.txt" />
</sharedListeners>
<trace autoflush="true" indentsize="4"></trace>
可以输出到console, xml, txt , 文件默认地址debug目录下。
以上可以用程序实现:
PresentationTraceSources.Refresh() //注册
PresentationTraceSources.RoutedEventSource.Listeners.Add(new DefaultTraceListener() )
PresentationTraceSources.RoutedEventSource.Switch.Level = SourceLevels.All
(详见http://msdn.microsoft.com/en-us/library/system.diagnostics.tracesource.aspx)
优点:
1, 把你需要的信息从output window中分离出来
2, 能够调试wpf其他地方的程序,而不仅仅是binding,
3, 能看到低层的信息,比如information ,warning, 这些在output window 中看不到
缺点:
1.显示某个空间下所有的信息,比如调试binding,会把所有的binding信息显示出来,而如果我只是想看一个binding的情况,需要寻找。
2.以上两种方法都是在binding失败的时候,如果成功,但是现实的东西不是自己的预期,怎么办?
三. .net3.5新特征: Set trace level Attached property
引用System.Diagnostics:
<xmlns:diagnostics="clr-namespace:System.Diagnostics;assembly=WindowsBase">
Add attached property
<Image Source="{Binding Path=Full, diagnostics:PresentationTraceSources.TraceLevel=High}" >
能把一个binding的从创建到获得具体值等信息全部显示出来
Output window:
System.Windows.Data Warning: 47 : Created BindingExpression (hash=17128415) for Binding (hash=11679222)
System.Windows.Data Warning: 49 : Path: 'FullName'
System.Windows.Data Warning: 51 : BindingExpression (hash=17128415): Default mode resolved to OneWay
System.Windows.Data Warning: 52 : BindingExpression (hash=17128415): Default update trigger resolved to PropertyChanged
System.Windows.Data Warning: 53 : BindingExpression (hash=17128415): Attach to System.Windows.Controls.Image.Source (hash=33986010)
System.Windows.Data Warning: 58 : BindingExpression (hash=17128415): Resolving source
System.Windows.Data Warning: 61 : BindingExpression (hash=17128415): Found data context element: Image (hash=33986010) (OK)
System.Windows.Data Warning: 69 : BindingExpression (hash=17128415): Activate with root item FileInfo (hash=54701786)
System.Windows.Data Warning: 98 : BindingExpression (hash=17128415): At level 0 - for FileInfo.FullName found accessor ReflectPropertyDescriptor(FullName)
System.Windows.Data Warning: 94 : BindingExpression (hash=17128415): Replace item at level 0 with FileInfo (hash=54701786), using accessor ReflectPropertyDescriptor(FullName)
System.Windows.Data Warning: 91 : BindingExpression (hash=17128415): GetValue at level 0 from FileInfo (hash=54701786) using ReflectPropertyDescriptor(FullName): 'C:"Documents and Settings"louya"Local Settings"Temporary Internet Files"Content.IE5"AN0U1MZ3"20081026150238d02bc[1].jpg'
System.Windows.Data Warning: 71 : BindingExpression (hash=17128415): TransferValue - got raw value 'C:"Documents and Settings"louya"Local Settings"Temporary Internet Files"Content.IE5"AN0U1MZ3"20081026150238d02bc[1].jpg'
System.Windows.Data Warning: 75 : BindingExpression (hash=17128415): TransferValue - implicit converter produced BitmapFrameDecode (hash=63141826)
System.Windows.Data Warning: 78 : BindingExpression (hash=17128415): TransferValue - using final value BitmapFrameDecode (hash=63141826)
优点:
允许在binding成功后知道更多,有利于查找逻辑错误
缺点:
给output window增加太多的东西
四.为binding 增加Converter class
为binding增加一个没有操作的converter ,设置断点从中看到binding的值
<Image Source="{Binding Path=FullName, Converter={StaticResource photoBindingConverter}}">
public class PhotoBindingConverter : IValueConverter
{
#region IValueConverter Members
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return value;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
Return value;
}
#endregion
}
优点:容易实现; 不依赖于output window;可以看到binding成功时候的信息
缺点:不能显示像设置trace level那么多的信息; 如果binding失败,可能到不了convert 方法。
五.Other Tricks
1. 用DependencyPropertyHelper.GetValueSource(DependencyObject,DependencyProperty)来查看DP的运行时信息:
ValueSource e = DependencyPropertyHelper.GetValueSource(Window1, Background);
ValueSource 是一个结构体,包括信息(MSDN):
Properties
Name | Description | |
---|---|---|
BaseValueSource | Gets a value of the BaseValueSource enumeration, which reports the source that provided the dependency property system with a value. | |
IsAnimated | Gets a value that declares whether the property is being animated. | |
IsCoerced | Gets a value that declares whether this value resulted from a CoerceValueCallback implementation applied to a dependency property. | |
IsExpression | Gets a value that declares whether this value resulted from an evaluated expression. This might be a BindingExpression supporting a binding, or an internal expression such as those that support the DynamicResource Markup Extension. |
BaseValueSource枚举数据为:
Member name | Description | |
---|---|---|
Unknown | Source is not known. This is the default value. | |
Default | Source is the default value, as defined by property metadata. | |
Inherited | Source is a value through property value inheritance. | |
DefaultStyle | Source is from a setter in the default style. The default style comes from the current theme. | |
DefaultStyleTrigger | Source is from a trigger in the default style. The default style comes from the current theme. | |
Style | Source is from a style setter of a non-theme style. | |
TemplateTrigger | Source is a trigger-based value in a template that is from a non-theme style. | |
StyleTrigger | Source is a trigger-based value of a non-theme style. | |
ImplicitStyleReference | Source is an implicit style reference (style was based on detected type or based type). This value is only returned for the Style property itself, not for properties that are set through setters or triggers of such a style. | |
ParentTemplate | Source is based on a parent template being used by an element. | |
ParentTemplateTrigger | Source is a trigger-based value from a parent template that created the element. | |
Local | Source is a locally set value. |
2. Snoop, reflector tool
3. 在使用xaml时, 我们经常会碰到XamlParseException, Visual Studio的默认这个异常处理包含信息太少,而且不能正确定位到xaml中异常所在位置。错误经常是这样:
An unhandled exception of type 'System.Windows.Markup.XamlParseException' occurred in PresentationFramework.dll
Additional information: Cannot create instance of 'Window1' defined in assembly 'GalaSoftLb.Wpf.MyApplication, Version=1.0.2629.15160, Culture=neutral, PublicKeyToken=null'. Exception has been thrown by the target of an invocation. Error in markup file 'Window1.xaml' Line 1 Position 9.
改进方法a:因为xaml解析是在InitializeComponent()中进行,可以参看比较详细的信息
public partial class Window1 : System.Windows.Window
{
public Window1()
{
try
{
InitializeComponent();
}
catch ( Exception ex )
{
// Log error (including InnerExceptions!)
// Handle exception
}
}
}
改进方法b:
Open the "Exceptions" window (Debug/Exceptions) in Visual Studio.
- Click "add"
- Add "System.Windows.Markup.XamlParseException"
- Check the box to break on throw for this exception.
- Hit F5!
You'll find that the XamlParseException you catch is much more descriptive, and will give the correct position in the xaml file.
Appendix: WPF tracing namespaces
· System.Windows.Data
This is probably the most useful trace source, and provides all kinds of information about WPF databinding, including warnings when it wasn’t possible to resolve a binding. This trace source does one thing that the other WPF trace sources do not, it enables itself automatically when you start your app in the debugger.
· System.Windows.DependencyProperty
This is probably the least useful trace source, and just provides information about registration of DPs. Unfortunately it doesn’t provide information such as property values being set and calculated.
· System.Windows.Freezable
This provides tracing about Freezable problems that don’t cause an exception. For example, if you call the CanFreeze method on a Freezable and it returns false, this tracing might be able to help you determine what exactly couldn’t be frozen.
· System.Windows.RoutedEvent
Provides tracing information on the routing of RoutedEvents, including a trace indicating what event listener handled the event.
· System.Windows.Media.Animation
Sends traces when storyboards are started, stopped, paused, resumed, etc.
· System.Windows.NameScope
Sends a trace when a name is registered, providing the name and the object.
· System.Windows.ResourceDictionary
Sends traces when a resource is set, removed, looked up, etc. Since there could be multiple resource dictionaries that define the same resource, this can be a useful way to determine where the resource is actually coming from.
· System.Windows.Markup
This sends traces when Xaml (or Baml) is loaded, with information such as the objects being created, the properties being set, and the type converters being used.
· System.Windows.Documents
Traces information about page formatting errors for paginated documents.