2011-08-19 70 views
0

解決我有一個工具條以下XAML:WPF ContextMenu.ItemsSource不從結合

<emsprim:SplitButton Mode="Split"> 
     <emsprim:SplitButton.Content> 
      <Image Source="images/16x16/Full Extent 1.png" /> 
     </emsprim:SplitButton.Content> 
     <emsprim:SplitButton.ContextMenu> 
      <ContextMenu ItemsSource="{Binding CommandGroups[ZoomToDefinedExtentsCmds]}"> 
       <ContextMenu.ItemContainerStyle> 
        <Style TargetType="MenuItem">        
         <Setter Property="Command" Value="{Binding Command}" /> 
         <Setter Property="CommandParameter" Value="{Binding ViewID}" /> 
         <Setter Property="Header" Value="{Binding Name}" /> 
         <Setter Property="Icon" Value="{Binding Icon}" /> 
        </Style> 
       </ContextMenu.ItemContainerStyle> 
      </ContextMenu> 
     </emsprim:SplitButton.ContextMenu>   
    </emsprim:SplitButton> 

其中CommandGroups [ZoomToDefinedExtentsCmds]是CommandViewModels的IEnumerable。問題是,當我點擊按鈕時,我看不到菜單項的列表。但是,如果我將相同的Datacontext綁定到菜單,如下所示:

<MenuItem ItemsSource="{Binding CommandGroups[ZoomToDefinedExtentsCmds]}" 
     Header="Zoom To"     
     Margin="5,1,5,0" > 
     <MenuItem.ItemContainerStyle> 
      <Style TargetType="MenuItem"> 
       <Setter Property="Command" Value="{Binding Command}" /> 
       <Setter Property="CommandParameter" Value="{Binding CommandParameter}" /> 
       <Setter Property="Header" Value="{Binding Name}" /> 
       <Setter Property="Icon" Value="{Binding Icon}" /> 
      </Style> 
     </MenuItem.ItemContainerStyle>  
    </MenuItem> 

我得到MenuItems的列表。關於這裏發生的任何想法,因爲在輸出VS窗口中沒有綁定錯誤。順便說一句,對於SplitButton代碼如下:

using System.ComponentModel; 
using System.Windows; 
using System.Windows.Controls; 
using System.Windows.Controls.Primitives; 
using System.Windows.Markup; 
using System.Diagnostics; 

namespace Controls.Dictionary.Primitives 
{ 
    /// <summary> 
    /// Implemetation of a Split Button 
    /// </summary> 
    [TemplatePart(Name = "PART_DropDown", Type = typeof(Button))] 
    [ContentProperty("Items")] 
    [DefaultProperty("Items")] 
    public class SplitButton : Button 
    { 
     // AddOwner Dependency properties 
     public static readonly DependencyProperty PlacementProperty; 
     public static readonly DependencyProperty PlacementRectangleProperty; 
     public static readonly DependencyProperty HorizontalOffsetProperty; 
     public static readonly DependencyProperty VerticalOffsetProperty; 

     /// <summary> 
     /// Static Constructor 
     /// </summary> 
     static SplitButton() 
     { 
      DefaultStyleKeyProperty.OverrideMetadata(typeof(SplitButton), new FrameworkPropertyMetadata(typeof(SplitButton))); 

      // AddOwner properties from the ContextMenuService class, we need callbacks from these properties 
      // to update the Buttons ContextMenu properties 
      PlacementProperty = ContextMenuService.PlacementProperty.AddOwner(typeof(SplitButton), new FrameworkPropertyMetadata(PlacementMode.MousePoint, OnPlacementChanged)); 
      PlacementRectangleProperty = ContextMenuService.PlacementRectangleProperty.AddOwner(typeof(SplitButton), new FrameworkPropertyMetadata(Rect.Empty, OnPlacementRectangleChanged)); 
      HorizontalOffsetProperty = ContextMenuService.HorizontalOffsetProperty.AddOwner(typeof(SplitButton), new FrameworkPropertyMetadata(0.0, OnHorizontalOffsetChanged)); 
      VerticalOffsetProperty = ContextMenuService.VerticalOffsetProperty.AddOwner(typeof(SplitButton), new FrameworkPropertyMetadata(0.0, OnVerticalOffsetChanged)); 
     } 

     /* 
     * Properties 
     * 
     */ 
     /// <summary> 
     /// The Split Button's Items property maps to the base classes ContextMenu.Items property 
     /// </summary> 
     public ItemCollection Items 
     { 
      get 
      { 
       EnsureContextMenuIsValid(); 
       return this.ContextMenu.Items; 
      } 
     } 
     /* 
     * Dependancy Properties & Callbacks 
     * 
     */ 
     /// <summary> 
     /// Placement of the Context menu 
     /// </summary> 
     public PlacementMode Placement 
     { 
      get { return (PlacementMode)GetValue(PlacementProperty); } 
      set { SetValue(PlacementProperty, value); } 
     } 
     /// <summary> 
     /// Placement Property changed callback, pass the value through to the buttons context menu 
     /// </summary> 
     private static void OnPlacementChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 
     { 
      SplitButton s = d as SplitButton; 
      if (s == null) return; 

      s.EnsureContextMenuIsValid(); 
      s.ContextMenu.Placement = (PlacementMode)e.NewValue; 
     } 


     /// <summary> 
     /// PlacementRectangle of the Context menu 
     /// </summary> 
     public Rect PlacementRectangle 
     { 
      get { return (Rect)GetValue(PlacementRectangleProperty); } 
      set { SetValue(PlacementRectangleProperty, value); } 
     } 
     /// <summary> 
     /// PlacementRectangle Property changed callback, pass the value through to the buttons context menu 
     /// </summary> 
     private static void OnPlacementRectangleChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 
     { 
      SplitButton s = d as SplitButton; 
      if (s == null) return; 
      s.EnsureContextMenuIsValid(); 
      s.ContextMenu.PlacementRectangle = (Rect)e.NewValue; 
     } 


     /// <summary> 
     /// HorizontalOffset of the Context menu 
     /// </summary> 
     public double HorizontalOffset 
     { 
      get { return (double)GetValue(HorizontalOffsetProperty); } 
      set { SetValue(HorizontalOffsetProperty, value); } 
     } 
     /// <summary> 
     /// HorizontalOffset Property changed callback, pass the value through to the buttons context menu 
     /// </summary> 
     private static void OnHorizontalOffsetChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 
     { 
      SplitButton s = d as SplitButton; 
      if (s == null) return; 

      s.EnsureContextMenuIsValid(); 
      s.ContextMenu.HorizontalOffset = (double)e.NewValue; 
     } 


     /// <summary> 
     /// VerticalOffset of the Context menu 
     /// </summary> 
     public double VerticalOffset 
     { 
      get { return (double)GetValue(VerticalOffsetProperty); } 
      set { SetValue(VerticalOffsetProperty, value); } 
     } 
     /// <summary> 
     /// VerticalOffset Property changed callback, pass the value through to the buttons context menu 
     /// </summary> 
     private static void OnVerticalOffsetChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 
     { 
      SplitButton s = d as SplitButton; 
      if (s == null) return; 

      s.EnsureContextMenuIsValid(); 
      s.ContextMenu.VerticalOffset = (double)e.NewValue; 
     } 

     /// <summary> 
     /// Defines the Mode of operation of the Button 
     /// </summary> 
     /// <remarks> 
     ///  The SplitButton two Modes are 
     ///  Split (default), - the button has two parts, a normal button and a dropdown which exposes the ContextMenu 
     ///  Dropdown   - the button acts like a combobox, clicking anywhere on the button opens the Context Menu 
     /// </remarks> 
     public SplitButtonMode Mode 
     { 
      get { return (SplitButtonMode)GetValue(ModeProperty); } 
      set { SetValue(ModeProperty, value); } 
     } 
     public static readonly DependencyProperty ModeProperty = DependencyProperty.Register("Mode", typeof(SplitButtonMode), typeof(SplitButton), new FrameworkPropertyMetadata(SplitButtonMode.Split)); 

     /* 
     * Methods 
     * 
     */ 
     /// <summary> 
     /// OnApplyTemplate override, set up the click event for the dropdown if present in the template 
     /// </summary> 
     public override void OnApplyTemplate() 
     { 
      base.OnApplyTemplate(); 

      // set up the event handlers 
      ButtonBase dropDown = this.Template.FindName("PART_DropDown", this) as ButtonBase; 
      if (dropDown != null) 
       dropDown.Click += DoDropdownClick; 

     } 

     /// <summary> 
     /// Make sure the Context menu is not null 
     /// </summary> 
     private void EnsureContextMenuIsValid() 
     { 
      if (ContextMenu == null) 
       ContextMenu = new ContextMenu(); 
     } 

     /* 
     * Events 
     * 
     */ 
     /// <summary> 
     /// Event Handler for the Drop Down Button's Click event 
     /// </summary> 
     /// <param name="sender"></param> 
     /// <param name="e"></param> 
     void DoDropdownClick(object sender, RoutedEventArgs e) 
     { 
      if (Mode == SplitButtonMode.Dropdown) 
       return; 

      if (ContextMenu == null || ContextMenu.HasItems == false) return; 

      ContextMenu.PlacementTarget = this; 
      ContextMenu.IsOpen = true; 

      e.Handled = true; 
     } 
    } 
} 

回答

2

問題通過顯式設置文本菜單的DataContext的解決。

的ContextMenu不可視樹的一部分,因此,不能解決的DataContext其「parent'-的是有一個問題是讓我每一次。

+0

你爲什麼將DataContext設置爲出於好奇? – fatty

+0

與我試圖綁定到的DataContext相同 - 與父工具欄相同。 –

0

在你的第二個代碼片段的MenuItem對象,是外SplitButton的作用域?如在,具有CommandGroups屬性定義的對象容器的直接孩子?

我問,因爲第一個片段中的ContextMenu將有一個空的DataContext,因此將無法看到CommandGroups財產

我有一個類似的問題,大約一年前,不幸的是,噸他唯一能解決這個問題的方法就是在代碼中定義ContextMenu,並在Command的Execute方法中定義ContextMenu。這使我能夠在代碼中分配ItemsSource。

要調試的DataContext(和其他具有約束力的相關問題,像這樣的),你應該自己創建像DebugConverter:

public class DebugConverter : IValueConverter 
{ 
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) 
    { 
     return value; 
    } 

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) 
    { 
     throw new NotImplementedException(); 
    } 
} 

這將幫助你調試一個棘手的結合問題,通過創建綁定,如:{Binding Converter={StaticResource debugConverter}}並通過設置在return value;線上的一個斷點。

+0

感謝您的迴應和轉換器建議。第二個代碼片段中的MenuItem不是SplitBUtton的一部分。 –