2014-01-25 83 views
2

這是一個問題。ContextMenu上的按鈕點擊不發射命令

我在按鈕單擊上顯示上下文菜單,菜單命令綁定到視圖模型中的ICommand。菜單顯示在按鈕點擊以及右擊上。問題是菜單點擊沒有發射時,我點擊按鈕,然後單擊上下文菜單,但我可以確認菜單正在工作時,我右鍵單擊按鈕,然後單擊菜單上。

<Button Grid.Row="3" Width="500" Height="30" Name="cmButton" > 
    Button with Context Menu 
    <Button.ContextMenu> 
     <ContextMenu DataContext="{Binding Path=PlacementTarget.DataContext, RelativeSource={RelativeSource Mode=Self}}" > 
      <MenuItem DataContext="{Binding}" Header="New Layout Element..." Command="{Binding Path=SubmitBtn}" />     
     </ContextMenu> 
    </Button.ContextMenu> 
    <Button.Style> 
     <Style TargetType="{x:Type Button}"> 
      <Style.Triggers> 
       <EventTrigger RoutedEvent="Click"> 
        <EventTrigger.Actions> 
         <BeginStoryboard> 
          <Storyboard> 
           <BooleanAnimationUsingKeyFrames Storyboard.TargetProperty="ContextMenu.IsOpen"> 
            <DiscreteBooleanKeyFrame KeyTime="0:0:0" Value="True"/> 
           </BooleanAnimationUsingKeyFrames> 
          </Storyboard> 
         </BeginStoryboard> 
        </EventTrigger.Actions> 
       </EventTrigger> 
      </Style.Triggers>      
     </Style> 
    </Button.Style> 
</Button> 

我可以證實,沒有什麼錯在我看來模型,因爲命令射擊時我做對按鈕單擊然後單擊快捷菜單上。

回答

7

PlacementTargetnull當您手動設置ContextMenu.IsOpen屬性時,因爲它通過右鍵單擊目標控件打開後才設置爲實際值。 (PopUpService類負責將此值設置爲實際目標)。

由於PlacementTarget是萬一null當您通過Storyboard打開它,綁定是不是能夠解決實際命令它綁定到。

所以,問題是你需要對ButtonDataContext傳遞給MenuItem,這樣的結合可以解決。 (MenuItem不是與按鈕相同的可視化樹)。這可以通過兩種方式來實現:


使用x:Reference(可在WPF 4.0及更高版本),但你需要聲明僞控制,以便它可以被引用到獲得DataContextVisibility設置爲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> 

另一個有趣的事情是Freezable對象繼承DataContext即使他們不VisualTree說謊,所以我們可以利用這個特性來克服的情況下,我們需要繼承DataContext

首先,我們需要create class inheriting from Freezable和揭露DP可以綁定到:

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)); 
} 

現在,我們可以用它在XAML這樣的:

<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> 
+1

羅希特,我嘗試第二種方法,它完美的作品。非常感謝你,今後與你聯繫。 –

+0

當然。很高興幫助賈斯汀.. :) –

+1

非常感謝,這是非常有幫助的 –

1

這是發生因爲ContextMenuDataContextnull,你只需要設置他從Button事件點擊。看樣品:

XAML:

<Button Content="More..." Click="ButtonMoreClick" ContextMenu="{StaticResource ContextMenu1}"/> 

代碼隱藏

private void ButtonMoreClick(object sender, RoutedEventArgs e) 
{ 
    var menu = (sender as Button).ContextMenu; 
    menu.DataContext = DataContext; 
    menu.IsOpen = true; 
} 

我希望幫助

相關問題