在尝试回答附近的“ Unit Testing WPF Bindings ” (单元测试WPF绑定)附近的问题时,我遇到了以下问题。.
找出WPF Data Binding接线设置不正确(或者断开了正确接线的东西)的最佳方法是什么? ?
尽管单元测试的方法似乎就像乔尔(Joel)的“撕下手臂以去除碎片”。
每个人似乎都致力于使用WPF进行数据绑定,这确实有其优点。
在尝试回答附近的“ Unit Testing WPF Bindings ” (单元测试WPF绑定)附近的问题时,我遇到了以下问题。.
找出WPF Data Binding接线设置不正确(或者断开了正确接线的东西)的最佳方法是什么? ?
尽管单元测试的方法似乎就像乔尔(Joel)的“撕下手臂以去除碎片”。
每个人似乎都致力于使用WPF进行数据绑定,这确实有其优点。
Answers:
在.NET 3.5中,引入了一种新的方法来专门输出有关特定数据绑定的跟踪信息。
这是通过新的System.Diagnostics.PresentationTraceSources.TraceLevel附加属性完成的,可以将其应用于任何绑定或数据提供程序。这是一个例子:
<Window x:Class="WpfApplication1.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:diag="clr-namespace:System.Diagnostics;assembly=WindowsBase"
Title="Debug Binding Sample"
Height="300"
Width="300">
<StackPanel>
<TextBox Name="txtInput" />
<Label>
<Label.Content>
<Binding ElementName="txtInput"
Path="Text"
diag:PresentationTraceSources.TraceLevel="High" />
</Label.Content>
</Label>
</StackPanel>
</Window>
这会将跟踪信息仅用于特定绑定在Visual Studio的“输出窗口”中,而无需任何跟踪配置。
最好的我能找到...
由于每个人都不能总是一直盯着“输出”窗口寻找绑定错误,所以我喜欢Option#2。将其添加到您的App.Config
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.diagnostics>
<sources>
<source name="System.Windows.Data" switchName="SourceSwitch" >
<listeners>
<add name="textListener" />
</listeners>
</source>
</sources>
<switches>
<add name="SourceSwitch" value="All" />
</switches>
<sharedListeners>
<add name="textListener"
type="System.Diagnostics.TextWriterTraceListener"
initializeData="GraveOfBindErrors.txt" />
</sharedListeners>
<trace autoflush="true" indentsize="4"></trace>
</system.diagnostics>
</configuration>
将其与良好的正则表达式扫描脚本配对以提取相关信息,您可以偶尔在输出文件夹中的GraveOfBindErrors.txt上运行
System.Windows.Data Error: 35 : BindingExpression path error: 'MyProperty' property not found on 'object' ''MyWindow' (Name='')'. BindingExpression:Path=MyProperty; DataItem='MyWindow' (Name=''); target element is 'TextBox' (Name='txtValue2'); target property is 'Text' (type 'String')
我使用此处介绍的解决方案将绑定错误转换为本地异常:http : //www.jasonbock.net/jb/Default.aspx? blog= entry.0f221e047de740ee90722b248933a28d
但是,WPF绑定中的正常情况是在用户输入无法转换为目标类型的情况下引发异常(例如,绑定到整数字段的TextBox;非数字字符串的输入会导致FormatException,输入的数字太大会导致OverflowException。类似的情况是当source属性的Setter引发异常时。
WPF处理此问题的方法是通过ValidatesOnExceptions = true和ValidationExceptionRule来向用户发送所提供的输入不正确的信号(使用异常消息)。
但是,这些异常也会发送到输出窗口,从而被BindingListener“捕获”,从而导致错误……显然不是您想要的行为。
因此,BindingListener
在以下情况下,我将类扩展为不抛出异常:
private static readonly IList<string> m_MessagesToIgnore =
new List<String>()
{
//Windows.Data.Error 7
//Binding transfer from target to source failed because of an exception
//Normal WPF Scenario, requires ValidatesOnExceptions / ExceptionValidationRule
//To cope with these kind of errors
"ConvertBack cannot convert value",
//Windows.Data.Error 8
//Binding transfer from target to source failed because of an exception
//Normal WPF Scenario, requires ValidatesOnExceptions / ExceptionValidationRule
//To cope with these kind of errors
"Cannot save value from target back to source"
};
公共中的修改行覆盖void WriteLine(string message):
....
if (this.InformationPropertyCount == 0)
{
//Only treat message as an exception if it is not to be ignored
if (!m_MessagesToIgnore.Any(
x => this.Message.StartsWith(x, StringComparison.InvariantCultureIgnoreCase)))
{
PresentationTraceSources.DataBindingSource.Listeners.Remove(this);
throw new BindingException(this.Message,
new BindingExceptionInformation(this.Callstack,
System.DateTime.Parse(this.DateTime),
this.LogicalOperationStack, int.Parse(this.ProcessId),
int.Parse(this.ThreadId), long.Parse(this.Timestamp)));
}
else
{
//Ignore message, reset values
this.IsFirstWrite = true;
this.DetermineInformationPropertyCount();
}
}
}
您可以使用WPF Inspector的触发器调试功能。只需从Codeplex下载该工具并将其附加到正在运行的应用程序即可。它还在窗口底部显示绑定错误。非常有用的工具!
这是有效调试/跟踪触发器的有用技术。它允许您记录所有触发操作以及要操作的元素:
http://www.wpfmentor.com/2009/01/how-to-debug-triggers-using-trigger.html
这对我们很有帮助,但我想补充一下那些觉得有用的人,Microsoft提供了一个与sdk一起读取该文件的实用程序。
在这里找到:http : //msdn.microsoft.com/en-us/library/ms732023.aspx
打开跟踪文件
1.通过使用命令窗口导航到WCF安装位置(C:\ Program Files \ Microsoft SDKs \ Windows \ v6.0 \ Bin),启动Service Trace Viewer,然后键入SvcTraceViewer.exe。(尽管我们在\ v7.0 \ Bin中找到了我们的)
注意:服务跟踪查看器工具可以与两种文件类型关联:.svclog和.stvproj。您可以在命令行中使用两个参数来注册和注销文件扩展名。
/ register:使用SvcTraceViewer.exe注册文件扩展名“ .svclog”和“ .stvproj”的关联
/ unregister:使用SvcTraceViewer.exe注销文件扩展名“ .svclog”和“ .stvproj”的关联
1.当Service Trace Viewer启动时,单击“文件”,然后指向“打开”。导航到您的跟踪文件的存储位置。
2.双击要打开的跟踪文件。
注意:在单击多个跟踪文件的同时按SHIFT键可以同时选择并打开它们。Service Trace Viewer合并所有文件的内容并显示一个视图。例如,您可以打开客户端和服务的跟踪文件。在配置中启用消息日志记录和活动传播时,此功能很有用。这样,您可以检查客户端和服务之间的消息交换。您也可以将多个文件拖到查看器中,或使用“项目”选项卡。有关更多详细信息,请参见“管理项目”部分。
3.要将其他跟踪文件添加到打开的集合中,请单击“文件”,然后指向“添加”。在打开的窗口中,导航到跟踪文件的位置,然后双击要添加的文件。
另外,对于日志文件的筛选,我们发现这些链接非常有用:
对于像我这样寻求以纯编程方式在给定跟踪级别启用所有WPF跟踪的人来说,这里有一段代码可以做到这一点。作为参考,它基于本文:WPF中的跟踪源。
它不需要更改app.config文件,也不需要更改注册表。
这是我在某些启动位置(应用程序等)使用它的方式:
....
#if DEBUG
WpfUtilities.SetTracing();
#endif
....
这是实用程序代码(默认情况下,它将所有警告发送到默认跟踪侦听器):
public static void SetTracing()
{
SetTracing(SourceLevels.Warning, null);
}
public static void SetTracing(SourceLevels levels, TraceListener listener)
{
if (listener == null)
{
listener = new DefaultTraceListener();
}
// enable WPF tracing
PresentationTraceSources.Refresh();
// enable all WPF Trace sources (change this if you only want DataBindingSource)
foreach (PropertyInfo pi in typeof(PresentationTraceSources).GetProperties(BindingFlags.Static | BindingFlags.Public))
{
if (typeof(TraceSource).IsAssignableFrom(pi.PropertyType))
{
TraceSource ts = (TraceSource)pi.GetValue(null, null);
ts.Listeners.Add(listener);
ts.Switch.Level = levels;
}
}
}