在WPF開發中,將ViewModel中對象綁定到UI上時,會出現明明已經將數據對象Binding到UI,可是UI上就是不顯示等等的問題。這篇博客將介紹WPF Data Binding調試相關的內容。express
ViewModel:ide
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:this
<StackPanel Margin="10"> <TextBlock Text="{Binding ID}" /> <TextBlock Text="{Binding Name}" Margin="0,10" /> <TextBlock Text="{Binding Age}" /> </StackPanel>
運行結果:spa
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: code
XAML:orm
<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方面的信息。xml
更多PresentationTraceSources信息能夠參考:對象
對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. } }
場景一和場景二中的方法解決因拼寫錯誤或者無明確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的調試方式,歡迎在評論區指出~