如何检测破碎的 WPF 数据绑定?

当我试图回答附近的一个问题“ 单元测试 WPF 绑定”时,我遇到了下面这个棘手的问题。
如果您的 WPF 数据绑定连接设置不正确(或者您刚刚破坏了一些正确连接的东西) ,那么最好的方法是什么?

虽然单元测试的方法看起来像 Joel 的“扯掉你的胳膊去除一个碎片”。.我正在寻找更简单的方法,以较少的开销检测到这一点。

似乎每个人都在很大程度上致力于使用 WPF 进行数据绑定。.它确实有它的优点。

35180 次浏览

我能找到的最好的..。

如何调试 WPF 绑定

由于每个人都不能总是留意输出窗口寻找绑定错误,我喜欢选项 # 2。也就是把这个添加到你的应用程序中。配置

<?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')

在.NET 3.5中,引入了一种新的方法来专门输出关于特定数据绑定的跟踪信息。

这是通过新的 系统。诊断。演示。跟踪源。跟踪级别附加属性实现的,您可以将该属性应用于任何绑定或数据提供程序。这里有一个例子:

<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>

这将只在 VisualStudio 的“输出”窗口中放置该特定绑定的跟踪信息,而不需要任何跟踪配置。

下面是一个有效调试/跟踪触发器的有用技术。它允许您记录所有触发器操作以及正在执行的元素:

Http://www.wpfmentor.com/2009/01/how-to-debug-triggers-using-trigger.html

这对我们非常有帮助,但是我想向那些认为这很有用的人补充一点,微软在 sdk 中提供了一个实用工具来读取这个文件。

在这里发现: http://msdn.microsoft.com/en-us/library/ms732023.aspx

打开跟踪文件

1. 通过使用命令窗口导航到 WCF 安装位置(C: 程序 微软文件 (SDKsWindowsv6.0 Bin) ,然后键入 (尽管我们在 v7.0 Bin 中找到了我们的版本)

注意: 服务跟踪查看器工具 可以与两种文件类型关联: . svclog 和. stvproj。您可以使用两个 命令行中要注册的参数 并注销文件扩展名。

注册: 文件扩展名“ . svclog”和 “ . stvproj”和 SvcTraceViewer.exe

/取消注册: 文件扩展名关联 “ . svclog”和“ . stvproj”与 SvcTraceViewer.exe

1. 当服务跟踪查看器启动时,单击“文件”,然后指向“打开”。 导航到您的 存储跟踪文件。

双击要打开的跟踪文件。

注意: 点击时按 SHIFT 选择多个跟踪文件,并 同时打开,服务 跟踪查看器合并所有 文件并呈现一个视图 例如,您可以打开 客户和服务,这是 在启用消息时非常有用 测井和活动传播 配置。通过这种方式,你可以 检查消息之间的交换 客户端和服务。您还可以拖动 将多个文件导入查看器,或者使用 参见管理 有关详细信息,请参阅项目部分。

要向打开的集合中添加其他跟踪文件,请单击“文件” 然后在窗口中指向 Add 打开,导航到位置 然后双击 要添加的文件。

另外,对于日志文件的过滤,我们发现这些链接非常有用:

Http://msdn.microsoft.com/en-us/library/ms751526.aspx

我使用这里提供的解决方案将绑定错误转换为本机异常: http://www.jasonbock.net/jb/Default.aspx?blog=entry.0f221e047de740ee90722b248933a28d

然而,WPF 绑定中的一个常见场景是在用户输入无法转换为目标类型时抛出异常(例如,绑定到整数字段的 TextBox; 非数字字符串的输入导致 FormatException,数字太大的输入导致 Overflow Exception)。类似的情况是源属性的 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"
};

Public 覆盖 void WriteLine (字符串消息)中的修改行:

        ....
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 检查器的触发器调试特性。只要下载这个工具,并将其附加到您的运行应用程序。它还显示窗口底部的绑定错误。 非常有用的工具!

enter image description here

对于像我这样的人来说,寻找一种在给定的跟踪级别上启用所有 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;
}
}
}

我对2021年的建议是:

最好的方法是使用来自 Nuget 的 Benoit Blanchon小型图书馆

他原来的职位在这里: https://stackoverflow.com/a/19610384/6296708

他的 GitHub 链接和更多关于如何使用它的信息 + Nuget 命令: https://github.com/bblanchon/WpfBindingErrors

它的特点(直到现在!) :

  • 对绑定错误抛出异常(+ 行号)
  • 如果源变量抛出任何异常,这个库将捕获它并显示它。
  • 单元测试也支持!

编码愉快!