我在ToolBar上有以下XAML:
<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]是一个IEnumerable的CommandViewModels。问题是,当我点击按钮时,我没有看到菜单项列表。但是,如果我将相同的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;
}
}
}
答案 0 :(得分:2)
通过显式设置ContextMenu的DataContext解决了问题。
ContextMenu不是可视化树的一部分,因此,它不会解析其“父母”的DataContext-每次都会让我感到厌烦。
答案 1 :(得分:0)
第二个代码段中的MenuItem对象是否在SplitButton范围之外?在,如何定义具有CommandGroups属性的对象容器的直接子节点?
我问,因为第一个代码段中的ContextMenu将具有null DataContext,因此无法看到CommandGroups属性。
一年前我遇到过类似的问题,遗憾的是,我能解决这个问题的唯一方法是在代码中定义ContextMenu,在Command的Execute方法中定义。这使我能够在代码中分配ItemsSource。
要调试DataContext(以及其他与Binding相关的问题),您应该自己创建一个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来帮助您调试麻烦的绑定问题:{Binding Converter={StaticResource debugConverter}}
并在return value;
行设置断点。