2011-08-19 29 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的一部分。 –