首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >WPF ContextMenu.ItemsSource未从绑定中解析

WPF ContextMenu.ItemsSource未从绑定中解析
EN

Stack Overflow用户
提问于 2011-08-19 11:50:40
回答 2查看 2.7K关注 0票数 0

我在ToolBar上有以下XAML:

代码语言:javascript
运行
复制
 <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>

其中CommandGroupsZoomToDefinedExtentsCmds是CommandViewModels的IEnumerable。问题是,当我点击按钮时,我看不到菜单项的列表。但是,如果我将相同的Datacontext绑定到菜单,如下所示:

代码语言:javascript
运行
复制
<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的名单。这里发生了什么,因为output VS窗口中没有绑定错误。顺便说一下,SplitButton的代码如下所示:

代码语言:javascript
运行
复制
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;
        }
    }
}
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2011-08-19 12:20:50

通过显式设置ContextMenu的DataContext解决了问题。

ContextMenu不是可视化树的一部分,因此,它不能解析它的“父元素”的DataContext --这是我每次都会遇到的问题。

票数 2
EN

Stack Overflow用户

发布于 2011-08-19 12:22:06

第二个代码片段中的MenuItem对象是否在SplitButton作用域之外?例如,定义了CommandGroups属性的对象容器的直接子容器?

我之所以这样问,是因为第一个代码片段中的ContextMenu将具有空DataContext,因此将无法看到CommandGroups属性。

不幸的是,一年前我也遇到过类似的问题,唯一能解决这个问题的方法就是在命令的Execute方法和代码中定义ContextMenu。这使我能够在代码中分配ItemsSource。

要调试DataContext (以及其他类似的绑定问题),您应该创建一个DebugConverter,如下所示:

代码语言:javascript
运行
复制
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
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/7116752

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档