在CustomControls中为MenuItems触发和捕获自定义路由命令

时间:2017-10-11 01:55:05

标签: c# wpf xaml custom-controls routed-commands

WPF。 .NET 4.6

我正在尝试学习RoutedCommands。在下面的代码中,我希望我的自定义类MenuItem通过触发 menuitem的已侦听的自定义路由命令来响应用户点击。当父菜单项从其包含的子节点接收routedcommand时,它将设置一个依赖项属性,允许可视树中的其他元素使用ElementName绑定进行绑定。到目前为止,我一直无法在父容器中捕获命令 - 所以我不确定它是否真的冒泡了。

  1. 如何将命令ChangeInkAttributes通过元素树路由到顶部的“InkMenu”元素?
  2. 子元素如何,例如“InkAndGestures”,从自定义控件,InkMenuItem中激发routedcommand,ChangeInkAttributes,
  3. 父类包含“InkMenu”如何捕获路由命令“InkAndGestures”?(最好在自定义控件中捕获路由命令 - 这是否可能?)
  4. 注意:我想避免代码隐藏中的任何/所有代码。

    我感谢任何帮助,因为对谷歌进行全面搜索未能展示出这种方法的一个很好的例子。

    TIA

    例如:

    <pn:InkMenuItem x:Name="InkMenu" Header="Ink"  > <---**Parent containter to set
    the dependency property and provide for ElementName binding.
    
    THESE ARE THE CHILDREN WHICH SHOULD SEND THE COMMAND TO THE PARENT "InkMenu"
    
                        <pn:InkMenuItem Header="Pen"    />
                        <pn:InkMenuItem Header="HighLighter"  />
                        <Separator />
                        <pn:InkMenuItem Header="RePen Selection"  />
                        <pn:InkMenuItem Header="Select Strokes"  />
                        <pn:InkMenuItem Header="Select All Strokes"  />
                        <Separator />
                        <pn:InkMenuItem Header="Erase By Stroke" />
                        <pn:InkMenuItem Header="Erase By Point"  />
                        <pn:InkMenuItem Header="Clear Strokes"   />
                        <Separator />
                        <pn:InkMenuItem Header="Show Recognition Layout" />
                        <pn:InkMenuItem x:Name="InkAndGestures"  Header="Ink And Getsures" IsCheckable="True"/>
                    </pn:InkMenuItem>
    

    我将InkMenuItem自定义控件简单地定义为:

    Generic.XAML:
    
     <Style TargetType="{x:Type local:InkMenuItem}" BasedOn="{StaticResource {x:Type MenuItem}}"/>
    
    InkMenuItem.cs:
        public class InkMenuItem : MenuItem
        {
            public static RoutedUICommand ChangeInkAttributes { get; }
    
            static InkMenuItem()
            {
                DefaultStyleKeyProperty.OverrideMetadata(typeof(InkMenuItem), new FrameworkPropertyMetadata(typeof(InkMenuItem)));
    
                //Instanciate the command
                ChangeInkAttributes = new RoutedUICommand("Change Ink Attributes", "ChangeInkAttributes", typeof(InkMenuItem));
    
                //Create the command binding
                CommandManager.RegisterClassCommandBinding(typeof(InkMenuItem), 
                    new CommandBinding(
                        /*Command Object */  ChangeInkAttributes, 
                        /*Execute*/          ChangeInkAttributes_Executed, 
                        /*Can Execute? */    ChangeInkAttributes_CanExecute));
    
            }
    
            public static void ChangeInkAttributes_Executed(object sender, ExecutedRoutedEventArgs e)
            {
                InkMenuItem inkmenuitem = sender as InkMenuItem;
    
                CommandParameter parameter = e.Parameter as CommandParameter;
    
                if (parameter != null)
                    parameter.CanEditBeExecuted = true;
    
                if (inkmenuitem != null)
                    inkmenuitem.changeInkAttributes();
            }
    
    
            public static void ChangeInkAttributes_CanExecute(object sender, CanExecuteRoutedEventArgs e)
            {
                e.CanExecute = true;  // can this command be executed?
                e.Handled = false;    // has this event been handled?
            }
    
    
            public override void OnApplyTemplate()
            {
                base.OnApplyTemplate();
            }
    
            // Raise the MyChecked event when the InkMenuItem is clicked
            protected override void OnClick()
            {
               // base.OnClick();
                ChangeInkAttributes.Execute(null,this);
            }
    
            private void changeInkAttributes()
            {
                var h = Header.ToString();
                MessageBox.Show(h+"23");
            }
    
        }
    

2 个答案:

答案 0 :(得分:1)

RoutedCommand从焦点元素中搜索可视树,向上搜索具有匹配CommandBinding的元素,为此特定Execute执行CommandBinding委托,然后停止。

微软的Nick Kramer在此声明:https://www.vistax64.com/avalon/852-routedcommand-doesnt-route-ui-tree.html

它没有任何进一步的路由或冒泡。

答案 1 :(得分:1)

拉了我留下的小头发之后,我可以放心地保证@ mm8是100%正确的。但是,我确实希望这个泡沫无论如何。所以,我改变了

ChangeInkAttributes_Executed事件以在其父InkMenuItem上重新抛出自身:

public static void ChangeInkAttributes_Executed(object sender, ExecutedRoutedEventArgs e)
        {
            InkMenuItem inkmenuitem = sender as InkMenuItem;

            CommandParameter parameter = e.Parameter as CommandParameter;

            if (parameter != null)
                parameter.CanEditBeExecuted = true;

            if (inkmenuitem != null)
                inkmenuitem.changeInkAttributes();

            // this only causes a loop, it does not bubble.
            // inkmenuitem.RaiseEvent(e);


            InkMenuItem parent = inkmenuitem.Parent as InkMenuItem;
            if (parent != null)
                parent.RaiseEvent(e);
        }

希望这有助于某人。