1. 程式人生 > >WPF 因設定不期望的DataContext,導致的繫結異常

WPF 因設定不期望的DataContext,導致的繫結異常

在MainWindow中,建立一個背景屬性BrushTest,並將其繫結至介面

 1 <Window x:Class="WpfApp8.MainWindow"
 2         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
 3         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
 4         xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
 5         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
 6         xmlns:local="clr-namespace:WpfApp8"
 7         mc:Ignorable="d"
 8         Title="MainWindow" Height="450" Width="800" x:Name="TheMainWindow">
 9     <Grid>
10         <local:UserControl1 BackgroundTest="{Binding BrushTest}"/>
11     </Grid>
12 </Window>
 1     public partial class MainWindow : Window
 2     {
 3         public MainWindow()
 4         {
 5             InitializeComponent();
 6             BrushTest = Brushes.Red;
 7             this.DataContext = this;
 8         }
10         public static readonly DependencyProperty BrushTestProperty = DependencyProperty.Register(
11             "BrushTest", typeof(SolidColorBrush), typeof(MainWindow), new PropertyMetadata(default(SolidColorBrush)));
13         public SolidColorBrush BrushTest
14         {
15             get { return (SolidColorBrush) GetValue(BrushTestProperty); }
16             set { SetValue(BrushTestProperty, value); }
17         }
18     }

並在視窗中新增一個UserControl,同樣新增一個BackgroundTest屬性,並將其繫結至介面。

 1 <UserControl x:Class="WpfApp8.UserControl1"
 2              xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
 3              xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
 4              xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
 5              xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
 6              xmlns:local="clr-namespace:WpfApp8"
 7              mc:Ignorable="d" 
 8              d:DesignHeight="450" d:DesignWidth="800">
 9     <Grid Background="{Binding BackgroundTest}">
10     </Grid>
11 </UserControl>
 1     public partial class UserControl1 : UserControl
 2     {
 3         public UserControl1()
 4         {
 5             InitializeComponent();
 6             this.DataContext = this;
 7         }
 8         public static readonly DependencyProperty BackgroundTestProperty = DependencyProperty.Register(
 9             "BackgroundTest", typeof(SolidColorBrush), typeof(UserControl1), new PropertyMetadata(default(SolidColorBrush)));
10         public SolidColorBrush BackgroundTest
11         {
12             get { return (SolidColorBrush) GetValue(BackgroundTestProperty); }
13             set { SetValue(BackgroundTestProperty, value); }
14         }
15     }

執行後,控制檯輸出繫結異常,背景設定並沒有生效。

System.Windows.Data Error: 40 : BindingExpression path error: 'BrushTest' property not found on 'object' ''UserControl1' (Name='')'.

BindingExpression:Path=BrushTest; DataItem='UserControl1' (Name=''); target element is 'UserControl1' (Name=''); target property is 'BackgroundTest' (type 'SolidColorBrush')

為何錯了呢?

因為UserControl設定了倆次DataContext,UserControl1內部設定的上下文覆蓋了主視窗設定的上下文。

視窗內<local:UserControl1 BackgroundTest="{Binding BrushTest}"/>繫結的值BrushTest,在UserControl下的上下文無法找到相關值,所以報錯了

 

此類繫結異常,一不小心還是很容易出現的。

在視窗設定了DataContext時(自身或者ViewModel),子控制元件也設定DataContext。有趣的是,在Xaml編輯時,使用Reshaper連結到的是視窗所在的上下文屬性。

所以,子控制元件設定DataContext時,需要關注下否有屬性被引用繫結外界資料。

建議子控制元件減少DataContext的使用,以上可以通過指定資料來源進行繫結。比如:

 1 <UserControl x:Class="WpfApp8.UserControl1"
 2              xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
 3              xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
 4              xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
 5              xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
 6              xmlns:local="clr-namespace:WpfApp8"
 7              mc:Ignorable="d" 
 8              d:DesignHeight="450" d:DesignWidth="800" x:Name="TheUserControl">
 9     <Grid Background="{Binding ElementName=TheUserControl,Path=BackgroundTest}">
10     </Grid>
11 </UserControl>

&n