为什么binding找不到目标?



我正在WPF中设计一个控件,它包含一个非常常见的模式:按钮打开下拉菜单。XAML的相关部分如下:

<ToggleButton x:Name="btnFilterPopup" IsChecked="{Binding IsOpen, ElementName=filterPopup, Mode=TwoWay, diag:PresentationTraceSources.TraceLevel=High}" Margin="{StaticResource DialogItemsExceptLeftMargin}" FontFamily="Marlett" Content="6"/>
<Popup x:Name="filterPopup" PlacementTarget="{Binding ElementName=btnFilterPopup}" Placement="Bottom">
<Border Background="{StaticResource ToolPopupBackgroundBrush}">
<StackPanel Orientation="Vertical" Margin="{StaticResource DialogItemsMargin}">
<CheckBox IsChecked="{Binding FilterCaseSensitive, Mode=TwoWay}" Margin="{StaticResource DialogItemsMargin}">Case sensitive</CheckBox>
<CheckBox IsChecked="{Binding FilterExcludes, Mode=TwoWay}" Margin="{StaticResource DialogItemsExceptTopMargin}">Exclude matching</CheckBox>
</StackPanel>
</Border>
</Popup>

然而,这两种绑定都不能找到它的目标。诊断如下所示:

System.Windows.Data Warning: 67 : BindingExpression (hash=46479497): Resolving source 
System.Windows.Data Warning: 70 : BindingExpression (hash=46479497): Found data context element: <null> (OK)
System.Windows.Data Warning: 74 :     Lookup name filterPopup:  queried ToggleButton (hash=36168141)
System.Windows.Data Warning: 67 : BindingExpression (hash=46479497): Resolving source 
System.Windows.Data Warning: 70 : BindingExpression (hash=46479497): Found data context element: <null> (OK)
System.Windows.Data Warning: 74 :     Lookup name filterPopup:  queried ToggleButton (hash=36168141)
System.Windows.Data Warning: 67 : BindingExpression (hash=46479497): Resolving source 
System.Windows.Data Warning: 70 : BindingExpression (hash=46479497): Found data context element: <null> (OK)
System.Windows.Data Warning: 74 :     Lookup name filterPopup:  queried ToggleButton (hash=36168141)
System.Windows.Data Warning: 67 : BindingExpression (hash=46479497): Resolving source 
System.Windows.Data Warning: 70 : BindingExpression (hash=46479497): Found data context element: <null> (OK)
System.Windows.Data Warning: 74 :     Lookup name filterPopup:  queried ToggleButton (hash=36168141)
System.Windows.Data Warning: 67 : BindingExpression (hash=46479497): Resolving source  (last chance)
System.Windows.Data Warning: 70 : BindingExpression (hash=46479497): Found data context element: <null> (OK)
System.Windows.Data Warning: 74 :     Lookup name filterPopup:  queried ToggleButton (hash=36168141)
System.Windows.Data Error: 4 : Cannot find source for binding with reference 'ElementName=filterPopup'. BindingExpression:Path=IsOpen; DataItem=null; target element is 'ToggleButton' (Name='btnFilterPopup'); target property is 'IsChecked' (type 'Nullable`1')
System.Windows.Data Error: 4 : Cannot find source for binding with reference 'ElementName=btnFilterPopup'. BindingExpression:(no path); DataItem=null; target element is 'Popup' (Name='filterPopup'); target property is 'PlacementTarget' (type 'UIElement')

为什么绑定不能找到它们的TargetElement?

Popup与放置目标不在同一可视树中。您可以使用RelativeSource绑定到Popup本身,以访问相应PlacementTargetDataContext

<ToggleButton x:Name="btnFilterPopup" IsChecked="{Binding IsOpen, ElementName=filterPopup, Mode=TwoWay, diag:PresentationTraceSources.TraceLevel=High}" Margin="{StaticResource DialogItemsExceptLeftMargin}" FontFamily="Marlett" Content="6"/>
<Popup x:Name="filterPopup" PlacementTarget="{Binding ElementName=btnFilterPopup}" Placement="Bottom">
<Border Background="{StaticResource ToolPopupBackgroundBrush}">
<StackPanel Orientation="Vertical" Margin="{StaticResource DialogItemsMargin}">
<CheckBox IsChecked="{Binding PlacementTarget.DataContext.FilterCaseSensitive, Mode=TwoWay, RelativeSource={RelativeSource AncestorType={x:Type Popup}}}" Margin="{StaticResource DialogItemsMargin}">Case sensitive</CheckBox>
<CheckBox IsChecked="{Binding PlacementTarget.DataContext.FilterExcludes, Mode=TwoWay, RelativeSource={RelativeSource AncestorType={x:Type Popup}}}">Exclude matching</CheckBox>
</StackPanel>
</Border>
</Popup>

或者,设置PopupDataContext参照其PlacementTarget

<ToggleButton x:Name="btnFilterPopup" IsChecked="{Binding IsOpen, ElementName=filterPopup, Mode=TwoWay, diag:PresentationTraceSources.TraceLevel=High}" Margin="{StaticResource DialogItemsExceptLeftMargin}" FontFamily="Marlett" Content="6" DataContext="{Binding PlacementTarget.DataContext, RelativeSource={RelativeSource Self}}"/>
<Popup x:Name="filterPopup" PlacementTarget="{Binding ElementName=btnFilterPopup}" Placement="Bottom">
<Border Background="{StaticResource ToolPopupBackgroundBrush}">
<StackPanel Orientation="Vertical" Margin="{StaticResource DialogItemsMargin}">
<CheckBox IsChecked="{Binding FilterCaseSensitive, Mode=TwoWay}" Margin="{StaticResource DialogItemsMargin}">Case sensitive</CheckBox>
<CheckBox IsChecked="{Binding FilterExcludes, Mode=TwoWay}" Margin="{StaticResource DialogItemsExceptTopMargin}">Exclude matching</CheckBox>
</StackPanel>
</Border>
</Popup>

一些控件如Popups不是可视树的一部分,因此无法通过这种绑定到达。在你的情况下,我会将IsOpen属性绑定到你的VM中的一个属性,并将其用于IsChecked绑定。PlacementTarget绑定也是一样,如果你不想或者不能在后面的代码中显式地设置它。

最新更新