PlacementTarget
is null
when you manually set ContextMenu.IsOpen
property because it is set to actual value only once it's open by right clicking on target control. (PopUpService
class is responsible for setting this value to actual target).
Since PlacementTarget
is null
in case when you open it via Storyboard
, binding is not able to resolve actual command it's binded to.
So, issue is you need to pass on the DataContext
of Button
to the MenuItem
so that binding can be resolved. (MenuItem
are not is same visual tree as that of button). That can be achieved via two ways:
Using x:Reference
(available in WPF 4.0 and higher) but you need to declare dummy control so that it can be referenced to get DataContext
with Visibility
set to Collapsed
.
<FrameworkElement x:Name="dummyControl" Visibility="Collapsed"/>
<Button Width="100" Height="30" Name="cmButton">
<Button.ContextMenu>
<ContextMenu>
<MenuItem Header="New Layout Element..."
Command="{Binding Path=DataContext.SubmitBtn,
Source={x:Reference dummyControl}}" />
</ContextMenu>
</Button.ContextMenu>
</Button>
Another interesting thing is Freezable
objects inherit DataContext
even if they don't lie in VisualTree
so we can use this feature to overcome situations where we need to inherit DataContext
.
First we need to create class inheriting from Freezable
and exposing DP which can be bind to:
public class BindingProxy : Freezable
{
#region Overrides of Freezable
protected override Freezable CreateInstanceCore()
{
return new BindingProxy();
}
#endregion
public object Data
{
get { return (object)GetValue(DataProperty); }
set { SetValue(DataProperty, value); }
}
public static readonly DependencyProperty DataProperty =
DependencyProperty.Register("Data", typeof(object), typeof(BindingProxy));
}
Now we can use it in XAML like this:
<Button Width="100" Height="30" Name="cmButton">
<Button.Resources>
<local:BindingProxy x:Key="proxy" Data="{Binding}"/>
</Button.Resources>
<Button.ContextMenu>
<ContextMenu>
<MenuItem Header="New Layout Element..."
Command="{Binding Path=Data.SubmitBtn,
Source={StaticResource proxy}}" />
</ContextMenu>
</Button.ContextMenu>
</Button>
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…