Reputation: 12833
I have a 3rd party SplitButton control that exposes some DropDownContent and a boolean IsOpen dp to control whether the drop down content is shown or not.
In the case the DropDownContent is a StackPanel with several Buttons, each of which is bound to a command in the view model. In addition to executing that command, clicking the button needs to close the open DropDown content, which I am doing with the AttachedBehavior below.
But my binding, which simple needs to get a reference to the ancestor SplitButton control doesn't work. In the binding, you will note I am trying to Find the first Ancestor control of type SplitButton. I do see however that the debug info says ancestor level 1, so I changed the level to as high as 4, but still with an error.
Can someone see what the fix is?
System.Windows.Data Error: 4 : Cannot find source for binding with reference 'RelativeSource FindAncestor, AncestorType='Xceed.Wpf.Toolkit.SplitButton', AncestorLevel='1''. BindingExpression:(no path); DataItem=null; target element is 'CloseDropDownContentBehavior' (HashCode=8896066); target property is 'DropDownButtonElement' (type 'SplitButton')
<DataTemplate x:Key="AddNewPartyTemplate">
<StackPanel HorizontalAlignment="Right" Margin="10">
<toolkit:SplitButton x:Name="theSplitButton" Content="{resx:Resx Subject_AddNewWithChoices}">
<toolkit:SplitButton.DropDownContent>
<StackPanel x:Name="theStackPanel">
<Button Content="{resx:Resx Person}" Command="{Binding AddNewPersonCommand}"
>
<i:Interaction.Behaviors>
<local:CloseDropDownContentBehavior
*** DropDownButtonElement="{Binding
RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type toolkit:SplitButton}}}"/>
</i:Interaction.Behaviors>
</Button>
...
</StackPanel>
</toolkit:SplitButton.DropDownContent>
</toolkit:SplitButton>
</StackPanel>
</DataTemplate>
public class CloseDropDownContentBehavior : Behavior<ButtonBase>
{
private ButtonBase _button;
protected override void OnAttached()
{
_button = AssociatedObject;
_button.Click += OnPartyButtonClick;
}
protected override void OnDetaching()
{
_button.Click -= OnPartyButtonClick;
}
// **** the point of it all
void OnPartyButtonClick(object sender, RoutedEventArgs e) { DropDownButtonElement.IsOpen = false; }
public static readonly DependencyProperty DropDownButtonElementProperty =
DependencyProperty.Register("DropDownButtonElement",
typeof(SplitButton), typeof(CloseDropDownContentBehavior), new UIPropertyMetadata(null, OnDropDownElementChanged));
public DropDownButton DropDownButtonElement
{
get { return (DropDownButton)GetValue(DropDownButtonElementProperty); }
set { SetValue(DropDownButtonElementProperty, value); }
}
private static void OnDropDownElementChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) {
}
}
Upvotes: 1
Views: 1983
Reputation: 178660
Guessing it's because Interaction.Behaviors
isn't part of the visual tree, so the binding won't find the ancestor. Have you tried simply:
DropDownElement="{Binding ElementName=theSplitButton}"
Update from comments: the solution in this case is to simply use x:Reference
:
DropDownElement="{x:Reference theSplitButton}"
Upvotes: 1
Reputation: 22445
i dont know the SplitButton.DropDownContent but if its behave like a context menu the following answer might help: WPF context menu whose items are defined as data templates
this trick is to bind with RelativeSource Self or Type ContextMenu and then set the Path to PlacementTarget.DataContext.YourProperty
Upvotes: 0