为什么绑定找不到目标?

Why cannot binding find the target?

我正在 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

弹出窗口等某些控件不是可视化树的一部分,因此无法通过那种绑定访问。在您的情况下,我会将 IsOpen 属性 绑定到您的 VM 中的 属性 并将其用于 IsChecked 绑定。对于 PlacementTarget 绑定也是如此,如果您不想或不能在代码隐藏中明确设置它。

A Popup 与放置目标不属于同一可视化树。您可以使用 RelativeSource 绑定到 Popup 本身,以访问相应 PlacementTarget.

DataContext
<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>