zoukankan      html  css  js  c++  java
  • [WPF] 如何调试Data Binding

    前言

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

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

    ViewModel:

    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            this.DataContext = new ViewModel() { Id = 100, Name = "Tom", Age = 24};
        }
    }
    
    public class ViewModel
    {
        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>

    运行结果:

    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

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

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

    public partial class App : Application
    {
        protected override void OnStartup(StartupEventArgs e)
        {
            PresentationTraceSources.Refresh();
            PresentationTraceSources.DataBindingSource.Listeners.Add(new ConsoleTraceListener());
            PresentationTraceSources.DataBindingSource.Listeners.Add(new DebugTraceListener());
            PresentationTraceSources.DataBindingSource.Switch.Level = SourceLevels.Warning | SourceLevels.Error;
            base.OnStartup(e);
        }
    }
    
    public class DebugTraceListener : TraceListener
    {
        public override void Write(string message)
        {
            // Write your log here.
        }
    
        public override void WriteLine(string message)
        {
            // Write your log here.
        }
    }

    场景三(使用ValueConverter来调试)

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

    public class DebugConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            Debugger.Break();
            return value;
        }
    
        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            Debugger.Break();
            return value;
        }
    }

    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的调试方式,欢迎在评论区指出~

  • 相关阅读:
    hive中如何查询除了其中某个字段剩余所有字段
    查找出不同环境下同一张表的数据差异
    pycharm中导入包失败的解决办法
    hive如何获取当前时间
    python-匿名函数
    Tensorflow报错:OMP: Error #15: Initializing libiomp5.dylib, but found libiomp5.dylib already initialized.
    Tensorflow中Tensor对象的常用方法(持续更新)
    Numpy中的广播机制,数组的广播机制(Broadcasting)
    重装conda
    matplotlib作图一例
  • 原文地址:https://www.cnblogs.com/yang-fei/p/7486118.html
Copyright © 2011-2022 走看看