[WPF] 如何调试Data Binding

摘要:
前言在WPF开发中,将ViewModel中对象绑定到UI上时,会出现明明已经将数据对象Binding到UI,但是UI上就是不显示等等的问题。这篇博客将介绍WPFDataBinding调试相关的内容。场景一ViewModel:publicpartialclassMainWindow:Window{publicMainWindow(){InitializeComponent();this.DataContext=newViewModel(){Id=100,Name="Tom",Age=24};}}publicclassViewModel{publicintId{get;set;}publicstringName{get;set;}publicintAge{get;set;}}XAML:运行结果:UI中Binding的ID值没有显示出来。在程序运行时,仔细查看VSOutput窗口,此时会有如下信息System.Windows.DataError:40:BindingExpressionpatherror:'ID'propertynotfoundon'object'''ViewModel''.BindingExpression:Path=ID;DataItem='ViewModel';targetelementis'TextBlock';targetpropertyis'Text'这段信息告诉提示说在ViewModel对象上没有找到ID属性,此时我们再去检查一下ViewModel发现,原来是将Id错误的写成了ID。

前言

在WPF开发中,将ViewModel中对象绑定到UI上时,会出现明明已经将数据对象Binding到UI,但是UI上就是不显示等等的问题。这篇博客将介绍WPF Data Binding调试相关的内容。

场景一(Binding的属性不存在)

ViewModel:

public partial classMainWindow : Window
{
    publicMainWindow()
    {
        InitializeComponent();
        this.DataContext = new ViewModel() { Id = 100, Name = "Tom", Age = 24};
    }
}
public classViewModel
{
    public int Id { get; set; }
    public string Name { get; set; }
    public int Age { get; set; }
}

XAML:

<StackPanel Margin="10">
    <TextBlock Text="{Binding ID}" />
    <TextBlock Text="{Binding Name}"Margin="0,10" />
    <TextBlock Text="{Binding Age}" />
</StackPanel>

运行结果:

[WPF] 如何调试Data Binding第1张

UI中Binding的ID值没有显示出来。请注意加粗的代码,在UI代码中,由于拼写错误,将Id写成了ID。但是这段代码在编译时不会报错,在VS Output窗口中也不会有提示/警告信息。在程序运行时,仔细查看VS Output窗口,此时会有如下信息 (对信息进行了精简)
System.Windows.Data Error: 40 : BindingExpression path error: 'ID' property not found on 'object' ''ViewModel' (HashCode=20915929)'. BindingExpression:Path=ID; DataItem='ViewModel' (HashCode=20915929); target element is 'TextBlock' (Name=''); target property is 'Text' (type 'String')

这段信息告诉提示说在ViewModel对象上没有找到ID属性,此时我们再去检查一下ViewModel发现,原来是将Id错误的写成了ID。一般这种错误的提示开头为:System.Windows.Data Error:

场景二(使用System.Diagnostics来追踪)

XAML:

<Window x:Class="WpfBindingDebug.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        mc:Ignorable="d"
        Title="MainWindow"Height="350"Width="525">
    <StackPanel>
        <TextBlock Text="{Binding Title}" />
    </StackPanel>
</Window>

将Title属性Binding到TextBlock的Text属性上面,XAML和C#代码中均未指定DataContext属性。编译项目并运行程序,在VS Output中没有任何提示/警告信息。此时应该如何调试呢?可以通过设置PresentationTraceSources对象的TraceLevel来强制WPF输出所有的Binding方面的信息。

更多PresentationTraceSources信息可以参考:

https://msdn.microsoft.com/en-us/library/system.diagnostics.presentationtracesources.tracelevel(v=vs.110).aspx

对XAML代码进行如下修改(注意加粗的代码行):

<Window x:Class="WpfBindingDebug.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:diag="clr-namespace:System.Diagnostics;assembly=WindowsBase"
        mc:Ignorable="d"
        Title="MainWindow"Height="350"Width="525">
    <StackPanel>
        <TextBlock Text="{Binding Title, diag:PresentationTraceSources.TraceLevel=High}" />
    </StackPanel>
</Window>

编译并运行程序,在VS Output窗口中可以找到关于Binding的信息(对信息进行了精简):

System.Windows.Data Warning: 56 : Created BindingExpression (hash=39201736) for Binding (hash=44325851)
System.Windows.Data Warning: 58 : Path: 'Title'
System.Windows.Data Warning: 60 : BindingExpression (hash=39201736): Default mode resolved to OneWay
System.Windows.Data Warning: 61 : BindingExpression (hash=39201736): Default update trigger resolved to PropertyChanged
System.Windows.Data Warning: 62 : BindingExpression (hash=39201736): Attach to System.Windows.Controls.TextBlock.Text (hash=17911681)
System.Windows.Data Warning: 67 : BindingExpression (hash=39201736): Resolving source
System.Windows.Data Warning: 70 : BindingExpression (hash=39201736): Found data context element: TextBlock (hash=17911681) (OK)
....
System.Windows.Data Warning: 67 : BindingExpression (hash=39201736): Resolving source
System.Windows.Data Warning: 70 : BindingExpression (hash=39201736): Found data context element: TextBlock (hash=17911681) (OK)
System.Windows.Data Warning: 71 : BindingExpression (hash=39201736): DataContext is null
System.Windows.Data Warning: 67 : BindingExpression (hash=39201736): Resolving source (last chance)
System.Windows.Data Warning: 70 : BindingExpression (hash=39201736): Found data context element: TextBlock (hash=17911681) (OK)
System.Windows.Data Warning: 78 : BindingExpression (hash=39201736): Activate with root item <null>
System.Windows.Data Warning: 106 : BindingExpression (hash=39201736): Item at level 0 is null - no accessor
System.Windows.Data Warning: 80 : BindingExpression (hash=39201736): TransferValue - got raw value {DependencyProperty.UnsetValue}
System.Windows.Data Warning: 88 : BindingExpression (hash=39201736): TransferValue - using fallback/default value ''
System.Windows.Data Warning: 89 : BindingExpression (hash=39201736): TransferValue - using final value ''

注意:在Visual Studio 2010中需要进行如下设置才能看到上面的提示信息:因为VS 2010默认将下面的设为Off。

Tools -> Options -> Debugging -> Output Window -> WPF Trace Settings -> Data Binding -> set to Warning

[WPF] 如何调试Data Binding第2张

程序一直在尝试寻找Visual Tree上的可以Binding的Title值,最终找到一个合适的,DependencyProperty.UnsetValue。

上述方法对查找单个页面Binding很有用,当然我们也可以全局的来收集这些Binding信息。在App.xaml.cs中添加:

public partial classApp : Application
{
    protected override voidOnStartup(StartupEventArgs e)
    {
        PresentationTraceSources.Refresh();
        PresentationTraceSources.DataBindingSource.Listeners.Add(newConsoleTraceListener());
        PresentationTraceSources.DataBindingSource.Listeners.Add(newDebugTraceListener());
        PresentationTraceSources.DataBindingSource.Switch.Level = SourceLevels.Warning |SourceLevels.Error;
        base.OnStartup(e);
    }
}
public classDebugTraceListener : TraceListener
{
    public override void Write(stringmessage)
    {
        //Write your log here.
}
    public override void WriteLine(stringmessage)
    {
        //Write your log here.
}
}

场景三(使用ValueConverter来调试)

场景一和场景二中的方法解决因拼写错误或者无明确DataContext时非常有效。不过有时候真正的通过VS进行调试一下,更加直观,便捷。可以使用实现一个简单的调试使用的Converter,然后将其Binding到目标上,

public classDebugConverter : IValueConverter
{
    public object Convert(object value, Type targetType, objectparameter, CultureInfo culture)
    {
        Debugger.Break();
        returnvalue;
    }
    public object ConvertBack(object value, Type targetType, objectparameter, CultureInfo culture)
    {
        Debugger.Break();
        returnvalue;
    }
}

Debugger.Break()的效果和VS中F9设置断点是一样的。
XAML

<Window x:Class="WpfBindingDebug.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfBindingDebug"
        mc:Ignorable="d"
        Title="MainWindow"Height="350"Width="525">
    <Window.Resources>
        <local:DebugConverter x:Key="DebugConverter" />
    </Window.Resources>
    <StackPanel>
        <TextBlock Text="{Binding Id, Converter={StaticResource DebugConverter}}" />
    </StackPanel>
</Window>

感谢您的阅读~如果您有其他关于Data Binding的调试方式,欢迎在评论区指出~

免责声明:文章转载自《[WPF] 如何调试Data Binding》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇DirectX学习笔记_关于Sprite.Draw2D的说明OO第一单元——表达式求导——总结下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

NestJS WebSocket 开始使用

使用NestJs提供WebSocket服务。本文会在新建项目的基础上增加2个类 Gateway 实现业务逻辑的地方 WebSocketAdapter WebSocket适配器 新建项目 新建一个项目来演示,用npm来管理项目。 nest new websocket-start 得到一个有基础功能的工程。 进入项目目录,安装2个库 npm i --sa...

WPF 常用控件属性

基础控件 转载 原文链接:https://blog.csdn.net/sheila_1988/java/article/details/7278638 §按钮:Button 和 RepeatButton 。§对话框: OpenFileDialog 、 PrintDialog和 SaveFileDialog。§数字墨迹: SaveFileDialog和 In...

ThreadPool.QueueUserWorkItem的性能问题

在WEB开发中,为了减少页面等待时间提高用户体验,我们往往会把一些浪费时间的操作放到新线程中在后台运行。 简单的实现代码就是: //代码一 new Thread(()=>{ //do something }).Start();   但是对于一个请求量大的网址这样做是很不现实的——每一个操作都要开启一个新线程,最终会因CPU不堪重负而...

使用PyCharm进行远程开发和调试

http://blog.csdn.net/ll641058431/article/details/53049453 使用PyCharm进行远程开发和调试 你是否经常要在Windows 7或MAC OS X上面开发Python或Web应用程序,但是它们最后需要在linux上面来运行呢? 我们经常会碰到开发时没有问题但是到了正式的Linux环境下面却出现问题。...

周末充电之WPF(三 ) .后台动态生成控件

布局 -连连看: 代码: 1 private void Window_Loaded_1(object sender, RoutedEventArgs e) 2 { 3 4 5 //动态创建行 6 for (int i = 0; i < 10; i++...

WPF学习笔记二 WPF命中测试

概述: WPF中的Canvas是常用的一个绘图控件,可以方便地在Canvas中添加我们需要处理的各种元素如:图片、文字等。但Canvas中元素增加到一定数量,并且有重合的时候,我们如何通过在Canvas中点击鼠标,获得我们想要的元素,然后再对该元素做出相应的控制? 命中测试,可以很好地解决这个问题 本文目的: 使用命中测试,选取Canvas中相应Ele...