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

时间:2008-12-03 13:04:22

标签: wpf data-binding

在尝试回答“Unit Testing WPF Bindings附近的问题”时,我遇到了以下琐碎的问题..
如果您的WPF数据绑定布线设置不正确(或者您刚刚破坏了正确接线的内容),最好的方法是什么?

尽管单元测试方法似乎就像Joel的“扯掉你的手臂去除碎片”一样......我正在寻找更容易,更少的开销方法来检测它。

每个人似乎都已经在WPF中大力宣传数据绑定......它确实有其优点。

8 个答案:

答案 0 :(得分:68)

在.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的输出窗口中为该特定绑定提供跟踪信息,而无需任何跟踪配置。

答案 1 :(得分:38)

我能找到最好的......

How can I debug WPF Bindings? by Beatriz Stollnitz

由于每个人都不能一直关注输出窗口寻找绑定错误,我喜欢选项#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')

答案 2 :(得分:5)

您可以使用WPF Inspector的触发器调试功能。只需从codeplex下载该工具并将其附加到正在运行的应用程序即可。它还显示窗口底部的绑定错误。 非常有用的工具!

enter image description here

答案 3 :(得分:4)

我使用此处提供的解决方案将绑定错误转换为本机异常: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"  
        };

public override中的修改行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();
            }
        }
    }

答案 4 :(得分:2)

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

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

答案 5 :(得分:2)

这对我们非常有帮助,但我想添加给那些发现这个有用的人,微软提供了一个实用程序,用于读取此文件的sdk。

在此处找到:http://msdn.microsoft.com/en-us/library/ms732023.aspx

  

打开跟踪文件

     

1.使用命令窗口启动服务跟踪查看器以导航到您的   WCF安装位置(C:\ Program   文件\微软   SDKs \ Windows \ v6.0 \ Bin),然后键入   SvcTraceViewer.exe。 (虽然我们在\ v7.0 \ Bin中发现了我们的

)      

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

     

/ register:注册协会   文件扩展名“.svclog”和   “.stvproj”与SvcTraceViewer.exe

     

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

     

1.当Service Trace Viewer启动时,单击“文件”,然后指向“打开”。   导航到您的位置   存储跟踪文件。

     

2.双击要打开的跟踪文件。

     

注意:单击时按SHIFT键   要选择的多个跟踪文件和   同时打开它们。服务   跟踪查看器合并所有内容   文件并呈现一个视图。对于   例如,您可以打开的跟踪文件   客户和服务。这是   启用消息后很有用   日志记录和活动传播   组态。通过这种方式,你可以   检查之间的消息交换   客户和服务。你也可以拖   多个文件进入查看器,或使用   项目选项卡。请参阅管理   项目部分了解更多详情。

     

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

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

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

答案 6 :(得分:1)

对于像我这样寻找在给定跟踪级别启用所有WPF跟踪的纯编程方式的人来说,这是一段代码。作为参考,它基于这篇文章:Trace sources in WPF

它不需要更改app.config文件,也不需要更改注册表。

这是我在一些初创公司(App等)中使用它的方式:

....
#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;
        }
    }
}

答案 7 :(得分:0)

我对 2021 年的建议:

最好的方法是使用来自 Nuget 的 Benoit Blanchon 小型库

他在这里的原始帖子:https://stackoverflow.com/a/19610384/6296708

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

它的功能(直到现在!):

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

快乐编码!