2.调试 WPF 应用程序

当我们的 WPF 程序未按预期工作时,我们需要对其进行调试,就像调试任何其他语言一样。 然而,一开始这似乎是一项艰巨的任务,因为 WPF 与其他语言有很大不同。 例如,在声明依赖属性时,为了方便起见,我们通常会添加一个 CLR 属性包装器。 但是,当属性值发生变化时,WPF 框架不会调用它,因此我们需要等待很长时间才能命中该 setter 中的断点

当我们测试新开发的代码时,我们需要能够检查数据绑定属性的值,并且有多种方法可以做到这一点,尽管有些方法并不明显。 在本章中,我们将调查一些重要的信息来源,以帮助我们找到代码中的错误。

我们将发现各种策略来帮助我们调试数据绑定值,并了解如何在遇到可怕的 XamlParseException 时追踪问题的实际原因。 我们将很快详细介绍所有这些主题,但现在,让我们首先从绝对基础知识开始。

利用输出窗口

当我们对 XAML 进行更改但没有看到我们期望在 UI 中看到的内容时,首先要查找错误的位置是 Visual Studio 的“输出”窗口。 如果此窗口尚不可见,则可以通过从“视图”菜单中选择“输出”选项或按 Ctrl + W 然后按 O 来显示它。

但是,如果您遇到绑定错误,但在“输出”窗口中没有看到任何对其的引用,则可能是因为您的 Visual Studio 当前未设置为向其输出调试信息。 您可以在 Visual Studio 选项对话框窗口中打开此功能。 导航至工具 | 选项| 调试| 输出窗口| 常规输出设置。

常规输出设置部分有多个可以打开和关闭的选项。 最重要的是“所有调试输出”和“异常消息”,但通常最好将它们全部设置为“开”。 设置后,绑定错误将以以下格式显示在输出窗口中:

System.Windows.Data Error: 40 : BindingExpression path error:
‘ViewName’ property not found on ‘object’ ‘‘MainViewModel’
(HashCode=3910657)’. BindingExpression:Path=ViewName;
DataItem=‘MainViewModel’ (HashCode=3910657); target element is ‘TextBox’
(Name=‘NameTextBox’); target property is ‘Text’ (type ‘String’)

  • MainViewModel 类型的对象中没有名为 ViewNameHashCode 值为 3910657 的公共属性。
  • 该错误是由指定为 ViewNameBinding.Path 值引发的,该值是在名为 NameTextBoxTextBox 实例的 Text 属性上设置的

可以使用描述性名称而不是具体细节来重写,如下所示:

System.Windows.Data Error: 40 : BindingExpression path error:
‘PropertyOfBindingSource’ property not found on ‘object’
‘‘TypeOfBindingSource’ (HashCode=HashCodeOfBindingSource)’.
BindingExpression:Path=UsedBindingPath; DataItem=‘TypeOfBindingSource’
(HashCode=HashCodeOfBindingSource); target element is ‘TypeOfBindingTarget’
(Name=‘NameOfBindingTarget’); target property is
‘PropertyOfBindingTarget’ (type ‘TypeOfBindingTargetProperty’)

现在我们有了解释这些值代表什么的“关键”,我们可以看到它们确实非常具有描述性。 我们不仅提供了数据绑定 UI 控件的名称(如果已设置)和使用的绑定路径,还提供了数据源的类型,以及正在使用的该类型的实际实例的哈希码。 用过的。

这些错误突出显示了 XAML 文件中所犯的错误。 此窗口中显示的错误类型将包括错误标记的绑定路径,例如使用不存在的属性名称或无效的绑定源路径。 虽然它不能捕获所有问题,但有一种方法可以让它输出额外的信息,帮助我们追踪更难以捉摸的问题。 为此,首先显示“选项”对话框窗口。 导航至工具 | 选项| 调试| 输出窗口| WPF 跟踪设置。

在这里,您可以找到许多选项,每个选项都有不同的输出级别:动画、数据绑定、依赖属性、文档、Freezable、HWND 托管、标记、名称范围、资源字典和路由事件。 各个级别的输出及其含义如下:

  • 关键:仅启用关键事件的跟踪
  • 错误:启用关键和错误事件的跟踪
  • 警告:启用对严重、错误和警告事件的跟踪
  • 信息:启用关键、错误、警告和信息事件的跟踪
  • 详细:启用关键、错误、警告、信息和详细事件的跟踪
  • ActivityTracing:启用对 Stop、Start、Suspend、Transfer 和 Resume 事件的跟踪

将“数据绑定”选项永久设置为“警告”或“错误”,而将其他选项设置为“关闭”是相当常见的。 使用这些选项时的一般经验法则是使用所需的最低级别,除非尝试查找问题,因为它们会减慢应用程序的运行速度。 但应该注意的是,这个额外的调试跟踪输出根本不会影响发布版本。

如果将数据绑定条目设置为“详细”或“全部”输出,并在运行应用程序时查看“输出”窗口,您就会明白为什么它会对性能产生负面影响。 即使不在输出窗口中显示此调试信息,当存在绑定错误时,WPF 框架仍将执行大量检查。 因此,清除显示的所有错误和警告非常重要,以最大限度地减少框架在尝试解决这些错误和警告时所做的工作量。

使演示跟踪源工作

尽管它很有用,但在某些情况下使用输出窗口是不够的。 也许我们现在有太多的输出需要查看,并且希望在下班回家的路上查看它,或者也许我们需要在部署应用程序后查看此类调试跟踪信息。 在这些情况和其他情况下,是时候启用 WPF 演示跟踪源了。

我们可以使用许多不同的跟踪源来为我们输出详细的跟踪数据。 该选项与 WPF 跟踪设置选项中的选项相同,事实上,在设置值后,输出窗口已经向我们显示了调试跟踪输出。

默认情况下,WPF 使用 DefaultTraceListener 对象将信息发送到输出窗口,但我们可以覆盖它和/或将输出配置为发送到文本和/或 XML 文件。

为此,我们需要更改 app.config 文件,该文件位于启动项目的根文件夹中。 我们需要添加一个 system.diagnostics 部分,并在其中添加源、开关和共享侦听器元素。 Switchs 元素保存着决定输出电平的开关,如上一节所述。

SharedListeners 元素指定我们要使用哪种输出。 这三种类型是:

System.Diagnostics.ConsoleTraceListener: 将跟踪发送到输出窗口
System.Diagnostics.TextWriterTraceListener: 输出到文本文件
System.Diagnostics.XmlWriterTraceListener: 输出到 XML 文件

最后,我们需要为每个要监听的跟踪源添加一个 source 元素,并指定要与其一起使用的开关和监听器。 因此,我们能够将不同的跟踪源输出到不同的介质并具有不同的输出级别。 这些跟踪源与 WPF 跟踪设置选项中的跟踪源相同,尽管在配置文件中,我们需要指定它们的全名。

选择如下:

System.Windows.Media.Animation
System.Windows.Data
System.Windows.DependencyProperty
System.Windows.Documents
System.Windows.Freezable
System.Windows.Interop.HwndHost
System.Windows.Markup
System.Windows.NameScope
System.Windows.ResourceDictionary
System.Windows.RoutedEvent
System.Windows.Shell

让我们看一个示例配置文件:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
    <startup>
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.1" />
    </startup>
    <system.diagnostics>
        <sources>
            <source name="System.Windows.Data" switchName="Switch">
                <listeners>
                    <add name
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

0neKing2017

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值