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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/337023/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-08 19:50:26  来源:igfitidea点击:

How to detect broken WPF Data binding?

wpfdata-binding

提问by Gishu

While trying to answer a question in the vicinity 'Unit Testing WPF Bindings' I had the following niggling question..
What's the best way to find if you have WPF Data Binding wiring setup incorrectly (or you just broke something that was wired up correctly) ?

虽然试图回答在附近“问题的单元测试WPF绑定”我有以下琐碎的问题..
什么是找到最好的方式,如果你有WPF数据绑定线路设置不当(或者你刚刚打破的东西,正确连接好) ?

Although the unit-testing approach seems to be like Joel's 'ripping off your arm to remove a splinter'.. I am looking around for easier less Overhead ways to detect this.

虽然单元测试方法似乎就像乔尔的“扯掉你的手臂以去除碎片”......我正在四处寻找更简单的方法来检测这一点。

Everyone seems to have committed themselves to data binding in a big way with WPF.. and it does have its merits.

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

采纳答案by Gishu

Best I could find...

我能找到的最好的...

How can I debug WPF Bindings? by Beatriz Stollnitz

如何调试 WPF 绑定?比阿特丽斯·斯托尔尼茨 (Beatriz Stollnitz)

Since everyone can't always keep one eye on the Output Window looking for Binding errors, I loved Option#2. Which is add this to your App.Config

由于每个人不能总是盯着输出窗口寻找绑定错误,我喜欢选项#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>

Pair that up with a good regex scan script to extract out relevant info, that you can run occasionally on the GraveOfBindErrors.txt in your output folder

将其与一个好的正则表达式扫描脚本配对以提取相关信息,您可以偶尔在输出文件夹中的 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')

回答by Enrico Campidoglio

In .NET 3.5 it was introduced a new way to specifically output tracing information about specific data bindings.

This is done through the new System.Diagnostics.PresentationTraceSources.TraceLevelattached property that you can apply to any binding or data provider. Here is an example:

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

This will put trace information for just that particular binding in Visual Studio's Output Window, without any tracing configuration required.

这将只在 Visual Studio 的输出窗口中放置该特定绑定的跟踪信息,而无需任何跟踪配置。

回答by Christian Moser

You can use the trigger debugging feature of WPF Inspector. Just download the tool from codeplex and attach it to your running app. It also shows binding errors on the bottom of the window. Very useful tool!

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

enter image description here

在此处输入图片说明

回答by Jeroen de Bekker

I use the solution presented here to turn binding errors into native Exceptions: http://www.jasonbock.net/jb/Default.aspx?blog=entry.0f221e047de740ee90722b248933a28d

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

However, a normal scenario in WPF bindings is to throw exceptions in case the user input cannot be converted to the target type (for instance, a TextBox bound to a integer field; the input of a non-numeric string results in a FormatException, the input of number that is too large results in an OverflowException). A similar case is when the Setter of the source property throws an exception.

但是,WPF 绑定中的正常情况是在用户输入无法转换为目标类型的情况下抛出异常(例如,绑定到整数字段的 TextBox;非数字字符串的输入导致 FormatException,输入过大的数字会导致溢出异常)。类似的情况是 source 属性的 Setter 抛出异常。

The WPF way of handling this is via ValidatesOnExceptions=true and ValidationExceptionRule to signal the user the supplied input is not correct (using the exception message).

WPF 处理此问题的方法是通过 ValidatesOnExceptions=true 和 ValidationExceptionRule 向用户发出信号,提供的输入不正确(使用异常消息)。

However, these exception are also send to the output window and thus 'caught' by the BindingListener, resulting in an error...clearly not the behaviour you'd want.

但是,这些异常也会发送到输出窗口,因此被 BindingListener '捕获',导致错误......显然不是您想要的行为。

Therefore, I expanded the BindingListenerclass to NOT throw an Exception in these cases:

因此,我将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"  
        };

Modified lines in public override void WriteLine(string message):

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();
            }
        }
    }

回答by Jeroen de Bekker

Here's a useful technique for debugging/tracing triggers effectively. It allows you to log all trigger actions along with the element being acted upon:

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

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

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

回答by ErocM

This was very helpful to us but I wanted to add to those who find this useful that there is a utility that Microsoft provides with the sdk to read this file.

这对我们非常有帮助,但我想向那些发现这很有用的人补充一点,Microsoft 随 sdk 提供了一个实用程序来读取此文件。

Found here: http://msdn.microsoft.com/en-us/library/ms732023.aspx

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

To open a trace file

1.Start Service Trace Viewer by using a command window to navigate to your WCF installation location (C:\Program Files\Microsoft SDKs\Windows\v6.0\Bin), and then type SvcTraceViewer.exe. (although we found ours in \v7.0\Bin)

Note: The Service Trace Viewer tool can associate with two file types: .svclog and .stvproj. You can use two parameters in command line to register and unregister the file extensions.

/register: register the association of file extensions ".svclog" and ".stvproj" with SvcTraceViewer.exe

/unregister: unregister the association of file extensions ".svclog" and ".stvproj" with SvcTraceViewer.exe

1.When Service Trace Viewer starts, click File and then point to Open. Navigate to the location where your trace files are stored.

2.Double-click the trace file that you want to open.

Note: Press SHIFT while clicking multiple trace files to select and open them simultaneously. Service Trace Viewer merges the content of all files and presents one view. For example, you can open trace files of both client and service. This is useful when you have enabled message logging and activity propagation in configuration. In this way, you can examine message exchange between client and service. You can also drag multiple files into the viewer, or use the Project tab. See the Managing Project section for more details.

3.To add additional trace files to the collection that is open, click File and then point to Add. In the window that opens, navigate to the location of the trace files and double-click the file you want to add.

打开跟踪文件

1.通过使用命令窗口导航到 WCF 安装位置 (C:\Program Files\Microsoft SDKs\Windows\v6.0\Bin) 来启动服务跟踪查看器,然后键入 SvcTraceViewer.exe。(虽然我们在 \v7.0\Bin 中找到了我们的)

注意:Service Trace Viewer 工具可以关联两种文件类型:.svclog 和 .stvproj。您可以在命令行中使用两个参数来注册和取消注册文件扩展名。

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

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

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

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

注意:在单击多个跟踪文件的同时按 SHIFT 可以同时选择和打开它们。Service Trace Viewer 合并所有文件的内容并呈现一个视图。例如,您可以打开客户端和服务的跟踪文件。当您在配置中启用消息日志记录和活动传播时,这很有用。通过这种方式,您可以检查客户端和服务之间的消息交换。您还可以将多个文件拖到查看器中,或使用“项目”选项卡。有关更多详细信息,请参阅管理项目部分。

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

Also, as for the filtering of the log file, we found these this link extremely helpful:

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

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

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

回答by Simon Mourier

For anyone like me looking for a pure programmatic way of enabling all WPF Tracing at a given Trace Level, here is a piece of code that does it. For reference, it's based on this article: Trace sources in WPF.

对于像我这样正在寻找在给定跟踪级别启用所有 WPF 跟踪的纯编程方式的任何人,这里有一段代码可以做到这一点。作为参考,它基于这篇文章:WPF 中的跟踪源

It doesn't requires a change in the app.config file, and it does not require to change the registry either.

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

This is how I use it, in some startup place (App, etc.):

这就是我在某些启动位置(应用程序等)中使用它的方式:

....
#if DEBUG
    WpfUtilities.SetTracing();
#endif
....

And here is the utility code (by default it sends all Warning to the Default Trace Listener):

这是实用程序代码(默认情况下,它将所有警告发送到默认跟踪侦听器):

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