无法获取 WPF 绑定错误跟踪信息以写入代码中配置的日志文件

Cannot get WPF binding error trace information to write to log file configured in code

我正在尝试调试我认为仅在一台生产机器上发生的 WPF 绑定问题 -- 我无法在开发人员机器上重现。为了做到这一点,我一直在尝试获取绑定跟踪信息以输出到日志文件。按照答案 like this one,我已经能够通过在 App.config:

中配置它来输出到硬编码位置
<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="c:\BindingErrors.log" />
  </sharedListeners>

  <trace autoflush="true" indentsize="4"/>
</system.diagnostics>

这在我的机器上运行良好,我对 c:\ 驱动器具有管理权限。问题是我想将日志写在用户有权访问的地方,例如他们的 TEMP 文件夹。所以我想做这样的事情,使用 %TEMP% 环境变量:

initializeData="%TEMP%\BindingErrors.log"

虽然这不起作用,我想它不会起作用 -- ;因此,按照该答案中的建议,我尝试通过代码而不是 App.config 配置输出。到目前为止,这是我尝试过的:

var listener = new 
    TextWriterTraceListener(Environment.ExpandEnvironmentVariables(
    @"%TEMP%\BindingErrors.log"), "myListener");

Trace.Listeners.Add(listener);   
Trace.WriteLine("foo"); // just to see if it works at all.
Trace.Flush();

但这只会将 foo 写入 %TEMP% 文件夹中的日志文件。它不会写入绑定错误。我试图复制 App.config 的内容,但是没有 Sources 集合,所以当我实例化 TraceSource 时,像这样:

var source = new TraceSource("mySource", SourceLevels.Information);

我不知道如何处理它,也没有 Listeners 集合可以添加我的 listener 实例。

MSDN 似乎并没有为我将所有内容整合在一起,或者我遗漏了一些关键细节。有人可以帮我弄清楚我做错了什么吗?

…there's no Listeners collection to which I can add my listener instance.

其实有:PresentationTraceSources.DataBindingSource.Listeners

属性 returns TraceSource 输出数据绑定消息时使用的对象。您可以向该源添加任何侦听器,例如您通过扩展 %TEMP% 环境变量并将其用作输出文件的目录在代码隐藏中创建的 TextWriterTraceListener

请注意,编程方法需要重新编译以更改输出位置,或者添加一些可以在 运行 时读取的其他配置值。另一种技术允许您在 app.config 文件中指定整个配置,方法是实现知道如何扩展环境变量的自定义 TraceListener

例如:

namespace TestSO39836570TraceListenerBindingErrors
{
    class EnvironmentAwareTextWriterTraceListener : TextWriterTraceListener
    {
        public EnvironmentAwareTextWriterTraceListener(string path)
            : base(Environment.ExpandEnvironmentVariables(path))
        { }

        public EnvironmentAwareTextWriterTraceListener(string path, string name)
            : base(Environment.ExpandEnvironmentVariables(path), name)
        { }
    }
}

然后在app.config文件中,可以指定监听器:

<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="TestSO39836570TraceListenerBindingErrors.EnvironmentAwareTextWriterTraceListener, TestSO39836570TraceListenerBindingErrors"
         initializeData="%temp%\BindingErrors.log"/>
  </sharedListeners>

  <trace autoflush="true" indentsize="4"/>
</system.diagnostics>

请注意,当指定在您自己的程序程序集中找到的自定义 TraceListener 类型时,您需要在 type 属性中指定程序集名称,方法是在完全限定类型名称之后带逗号,然后是程序集名称(在上面的示例中,类型的命名空间与程序集名称相同,根据 Visual Studio 中创建的项目的默认值)。

您当然可以选择比我在这里使用的更短的命名空间和类型名称。 :)