This article is currently in the process of being translated into Vietnamese (~99% done).
Debugging data bindings
Vì các data bindings được evaluated trong thời gian chạy và không có exceptions nào được đưa ra khi chúng thất bại, một ràng buộc xấu đôi khi có thể rất khó theo dõi. Những vấn đề này có thể xảy ra trong một số tình huống khác nhau, nhưng một vấn đề phổ biến là khi bạn cố gắng liên kết với một tài sản không tồn tại, vì bạn nhớ tên của nó sai hoặc vì bạn chỉ viết sai chính tả. Đây là một ví dụ:
<Window x:Class="WpfTutorialSamples.DataBinding.DataBindingDebuggingSample"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="DataBindingDebuggingSample" Height="100" Width="200">
<Grid Margin="10" Name="pnlMain">
<TextBlock Text="{Binding NonExistingProperty, ElementName=pnlMain}" />
</Grid>
</Window>
Cửa sổ đầu ra
Vị trí đầu tiên bạn sẽ nhìn là ở cửa sổ Output của Visual Studio. Nó nằm ở dưới cửa sổ Visual Studio của bạn, hoặc bạn có thể kích hoạt chúng bằng cách sử dụng phím tắt [Ctrl+Alt+O]. Ở đây sẽ tải hêt output từ trình sửa lỗi, nhưng bạn nên tìm ở đâu đó một dòng giống như thế này, khi chạy ví dụ trên:
System.Windows.Data Error: 40 : BindingExpression path error: 'NonExistingProperty' property not found on 'object' ''Grid' (Name='pnlMain')'. BindingExpression:Path=NonExistingProperty; DataItem='Grid' (Name='pnlMain'); target element is 'TextBlock' (Name=''); target property is 'Text' (type 'String')
Trông có vẻ một chút phức tạp, chủ yếu bởi vì không có ngắt dòng được sử dụng trong thông báo dài này, nhưng phần quan trọng là ở:
'NonExistingProperty' property not found on 'object' ''Grid' (Name='pnlMain')'.
Nó nói rằng bạn đã cố sử dụng thuộc tính có tên là "NonExistingProperty" trong đối tượng kiểu Grid, với tên là pnlMain. Rất ngắn gọn và sẽ giúp bạn sửa chữa chính xác tên của thuộc tính hoặc liên kết các đối tượng thực tế, nếu đó là vấn đề.
Adjusting the trace level
Ví dụ ở trên rất dễ sửa chữa, bởi vì WPF thể hiện rất rõ ràng việc nó đang cố gắng làm gì đó và vì sao nó không hoạt động. Hãy xem xét ví dụ tiếp theo:
<Window x:Class="WpfTutorialSamples.DataBinding.DataBindingDebuggingSample"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="DataBindingDebuggingSample" Height="100" Width="200">
<Grid Margin="10">
<TextBlock Text="{Binding Title}" />
</Grid>
</Window>
Tôi đang cố gắng liên kết với "Title", nhưng trên đối tượng nào? Như đã nêu trong bài viết về bối cảnh dữ liệu, WPF sẽ sử dụng thuộc tính DataContext trên TextBlock ở đây, có thể được kế thừa theo cấu trúc phân cấp điều khiển, nhưng trong ví dụ này, tôi đã quên gán bối cảnh dữ liệu. Điều này về cơ bản có nghĩa là tôi đang cố gắng để có được một tài sản trên một đối tượng NULL. WPF sẽ tập hợp rằng đây có thể là một ràng buộc hoàn toàn hợp lệ, nhưng đối tượng chưa được khởi tạo, và do đó nó sẽ không báo lỗi về điều đó. Nếu bạn chạy ví dụ này và tìm trong cửa sổ đầu ra, bạn sẽ không thấy bất kỳ lỗi ràng buộc nào.
Tuy nhiên, đối với các trường hợp đây không phải là hành vi mà bạn mong đợi, có một cách để buộc WPF nói với bạn về tất cả các vấn đề ràng buộc mà nó gặp phải. Nó có thể được thực hiện bằng cách đặt TraceLevel trên đối tượng PresentationTraceSource, có thể được tìm thấy trong không gian tên System.Diagnostics:
<Window x:Class="WpfTutorialSamples.DataBinding.DataBindingDebuggingSample"
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="DataBindingDebuggingSample" Height="100" Width="200">
<Grid Margin="10">
<TextBlock Text="{Binding Title, diag:PresentationTraceSources.TraceLevel=High}" />
</Grid>
</Window>
Lưu ý rằng tôi đã thêm một tham chiếu đến không gian tên System.Diagnostics ở trên cùng, và sau đó sử dụng thuộc tính trên liên kết. WPF sẽ cung cấp cho bạn tải về thông tin về ràng buộc cụ thể này trong cửa sổ đầu ra :
System.Windows.Data Warning: 55 : Created BindingExpression (hash=2902278) for Binding (hash=52760599)
System.Windows.Data Warning: 57 : Path: 'Title'
System.Windows.Data Warning: 59 : BindingExpression (hash=2902278): Default mode resolved to OneWay
System.Windows.Data Warning: 60 : BindingExpression (hash=2902278): Default update trigger resolved to PropertyChanged
System.Windows.Data Warning: 61 : BindingExpression (hash=2902278): Attach to System.Windows.Controls.TextBlock.Text (hash=18876224)
System.Windows.Data Warning: 66 : BindingExpression (hash=2902278): Resolving source
System.Windows.Data Warning: 69 : BindingExpression (hash=2902278): Found data context element: TextBlock (hash=18876224) (OK)
System.Windows.Data Warning: 70 : BindingExpression (hash=2902278): DataContext is null
System.Windows.Data Warning: 64 : BindingExpression (hash=2902278): Resolve source deferred
System.Windows.Data Warning: 66 : BindingExpression (hash=2902278): Resolving source
System.Windows.Data Warning: 69 : BindingExpression (hash=2902278): Found data context element: TextBlock (hash=18876224) (OK)
System.Windows.Data Warning: 70 : BindingExpression (hash=2902278): DataContext is null
System.Windows.Data Warning: 66 : BindingExpression (hash=2902278): Resolving source
System.Windows.Data Warning: 69 : BindingExpression (hash=2902278): Found data context element: TextBlock (hash=18876224) (OK)
System.Windows.Data Warning: 70 : BindingExpression (hash=2902278): DataContext is null
System.Windows.Data Warning: 66 : BindingExpression (hash=2902278): Resolving source
System.Windows.Data Warning: 69 : BindingExpression (hash=2902278): Found data context element: TextBlock (hash=18876224) (OK)
System.Windows.Data Warning: 70 : BindingExpression (hash=2902278): DataContext is null
System.Windows.Data Warning: 66 : BindingExpression (hash=2902278): Resolving source (last chance)
System.Windows.Data Warning: 69 : BindingExpression (hash=2902278): Found data context element: TextBlock (hash=18876224) (OK)
System.Windows.Data Warning: 77 : BindingExpression (hash=2902278): Activate with root item <null>
System.Windows.Data Warning: 105 : BindingExpression (hash=2902278): Item at level 0 is null - no accessor
System.Windows.Data Warning: 79 : BindingExpression (hash=2902278): TransferValue - got raw value {DependencyProperty.UnsetValue}
System.Windows.Data Warning: 87 : BindingExpression (hash=2902278): TransferValue - using fallback/default value ''
System.Windows.Data Warning: 88 : BindingExpression (hash=2902278): TransferValue - using final value ''
Bằng cách đọc qua danh sách, bạn thực sự có thể thấy toàn bộ quá trình mà WPF trải qua để cố gắng tìm một giá trị phù hợp cho điều khiển TextBlock của bạn. Nhiều lần bạn sẽ thấy nó không thể tìm thấy DataContext thích hợp và cuối cùng, nó sử dụng {DependencyProperty.UnsetValue} mặc định chuyển thành một chuỗi trống.
Using the real debugger
Thủ thuật trên có thể rất tốt để chẩn đoán một ràng buộc xấu, nhưng đối với một số trường hợp, làm việc với trình gỡ lỗi thực sự dễ dàng và dễ chịu hơn. Các ràng buộc thực sự không hỗ trợ điều này, vì chúng đang được xử lý sâu bên trong WPF, nhưng bằng cách sử dụng Trình chuyển đổi, như được hiển thị trong bài viết trước, bạn thực sự có thể nhảy vào quá trình này và bước qua nó. Bạn không thực sự cần một Trình chuyển đổi làm bất cứ điều gì hữu ích, bạn chỉ cần một cách vào quy trình ràng buộc và một trình chuyển đổi giả sẽ đưa bạn đến đó:
<Window x:Class="WpfTutorialSamples.DataBinding.DataBindingDebuggingSample"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:self="clr-namespace:WpfTutorialSamples.DataBinding"
Title="DataBindingDebuggingSample" Name="wnd" Height="100" Width="200">
<Window.Resources>
<self:DebugDummyConverter x:Key="DebugDummyConverter" />
</Window.Resources>
<Grid Margin="10">
<TextBlock Text="{Binding Title, ElementName=wnd, Converter={StaticResource DebugDummyConverter}}" />
</Grid>
</Window>
using System;
using System.Windows;
using System.Windows.Data;
using System.Diagnostics;
namespace WpfTutorialSamples.DataBinding
{
public partial class DataBindingDebuggingSample : Window
{
public DataBindingDebuggingSample()
{
InitializeComponent();
}
}
public class DebugDummyConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
Debugger.Break();
return value;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
Debugger.Break();
return value;
}
}
}
Trong tệp Code-behind, chúng tôi xác định DebugDummyConverter. Trong các phương thức Convert() và ConvertBack(), chúng tôi gọi Debugger.Break(), có tác dụng tương tự như đặt điểm dừng trong Visual Studio, sau đó trả về giá trị được cung cấp cho chúng tôi.
Trong phần đánh dấu, chúng tôi thêm một tham chiếu đến trình chuyển đổi của chúng tôi trong tài nguyên cửa sổ và sau đó chúng tôi sử dụng nó trong liên kết của chúng tôi. Trong một ứng dụng trong thế giới thực, bạn nên xác định trình chuyển đổi trong một tệp của riêng mình và sau đó thêm tham chiếu vào nó trong App.xaml, để bạn có thể sử dụng nó trên tất cả các ứng dụng mà không phải tạo một tham chiếu mới cho nó trong mỗi ứng dụng cửa sổ, nhưng đối với ví dụ này, ở trên nên làm tốt.
Nếu bạn chạy ví dụ, bạn sẽ thấy trình gỡ lỗi bị hỏng ngay khi WPF cố gắng tìm nạp giá trị cho tiêu đề của cửa sổ. Bây giờ bạn có thể kiểm tra các giá trị được cung cấp cho phương thức Convert() hoặc thậm chí thay đổi chúng trước khi tiếp tục, sử dụng các khả năng sửa lỗi tiêu chuẩn của Visual Studio.
Nếu trình gỡ lỗi không bao giờ bị hỏng, điều đó có nghĩa là trình chuyển đổi không được sử dụng. Điều này thường chỉ ra rằng bạn có một biểu thức ràng buộc không hợp lệ, có thể được chẩn đoán và sửa chữa bằng các phương pháp được mô tả trong phần đầu của bài viết này. Thủ thuật chuyển đổi giả chỉ để kiểm tra các biểu thức ràng buộc hợp lệ.