UWP开发砸手机系列—— “讲述人”识别自定义控件Command

我们可以看到通过Behaviors绑定了Command,在Tapped事件发生时触发ChangeTitleCommand。

我们再来对比一下系统控件Button的写法:

<Button Command="{x:Bind ChangeTitleCommand}">I am Button</Button>

在“讲述人”模式下,点击上面这个Button按钮,“讲述人”除了会念出“I am Button Button.”这句话以外,还会补充一句“Double tap to activate.”这时双击Button将会触发ChangeTitleCommand。

其中不一样的地方无非就是Button自带有名为“Command”的,类型为ICommand的依赖属性(DependencyProperty):

public System.Windows.Input.ICommand Command { get; set; }
    Member of Windows.UI.Xaml.Controls.Primitives.ButtonBase

而我们自定义的CanReadGrid,则是通过附加属性(Attached Property)来获得绑定Command的能力。

附件属性也是一种特殊的依赖属性,二者殊归同路。既然Button通过依赖属性可以做到的事情,附加属性一样可以完成。

想要弄明白Button的Command是如何被调用的,最简单的办法就是去查看源码呗:

  publicclass ButtonAutomationPeer : ButtonBaseAutomationPeer, IInvokeProvider
    {
        ///<summary>Initializes a new instance of the <see cref="T:System.Windows.Automation.Peers.ButtonAutomationPeer" /> class.</summary>        ///<param name="owner">The element associated with this automation peer.</param>        public ButtonAutomationPeer(Button owner) : base(owner)
        {
        }




        ///<summary>Gets the name of the control that is associated with this UI Automation peer.</summary>        ///<returns>A string that contains "Button".</returns>        protectedoverridestring GetClassNameCore()
        {
            return"Button";
        }




        ///<summary>Gets the control type of the element that is associated with the UI Automation peer.</summary>        ///<returns>        ///   <see cref="F:System.Windows.Automation.Peers.AutomationControlType.Button" />.</returns>        protectedoverride AutomationControlType GetAutomationControlTypeCore()
        {
            return AutomationControlType.Button;
        }




        ///<summary>Gets the object that supports the specified control pattern of the element that is associated with this automation peer.</summary>        ///<returns>If <paramref name="patternInterface" /> is <see cref="F:System.Windows.Automation.Peers.PatternInterface.Invoke" />, this method returns a this pointer, otherwise this method returns null.</returns>        ///<param name="patternInterface">A value in the enumeration.</param>        publicoverrideobject GetPattern(PatternInterface patternInterface)
        {
            if (patternInterface == PatternInterface.Invoke)
            {
                returnthis;
            }
            returnbase.GetPattern(patternInterface);
        }




        ///<summary>This type or member supports the Windows Presentation Foundation (WPF) infrastructure and is not intended to be used directly from your code.</summary>        void IInvokeProvider.Invoke()
        {
            if (!base.IsEnabled())
            {
                thrownew ElementNotEnabledException();
            }
            base.Dispatcher.BeginInvoke(DispatcherPriority.Input, new DispatcherOperationCallback(delegate(object param)
            {
                ((Button)base.Owner).AutomationButtonBaseClick();
                returnnull;
            }), null);
        }
    }

果不其然发现了上一篇我们提到的GetClassNameCore,GetAutomationControlTypeCore,GetPattern三个方法。另外还有一个奇怪的void IInvokeProvider.Invoke()。这货看名字也能猜出来是干啥的啦,这货竟然去调了Button类里的Click方法……

知道真相的我眼泪流出来……搞啥呢,那我在这里调一下Command.Execute不就成了!
首先我们给CanReadGrid添加ExecuteCommand方法,该方法通过DependencyObject的GetValue方法一层层拿到Command,然后执行Execute。

publicclass CanReadGrid : Grid
    {
        protectedoverride AutomationPeer OnCreateAutomationPeer()
        {
            returnnew GridAutomationPeer((this));
        }




        publicvoid ExecuteCommand()
        {
            var behaviors = Interaction.GetBehaviors(this);
            var actions = behaviors[0].GetValue(EventTriggerBehavior.ActionsProperty) as ActionCollection;
            var command = actions[0].GetValue(InvokeCommandAction.CommandProperty) as ICommand;
            command.Execute(null);
        }
    }

第二步就是完善GridAutomatioPeer,这里需要注意的是IInvokeProvider这个接口,通过Button的源码推测具有Action的控件需要实现这个接口的Invoke方法来执行操作。我们也是在Invoke方法里来调用CanReadGrid类里的ExecuteCommand方法。

publicclass GridAutomationPeer : FrameworkElementAutomationPeer, IInvokeProvider
    {
        public GridAutomationPeer(Grid owner)
                : base(owner)
        {
            
        }




        publicasyncvoid Invoke()
        {
            await CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal,
                () =>                {
                    ((CanReadGrid)base.Owner).ExecuteCommand();
                });
        }




        protectedoverrideobject GetPatternCore(PatternInterface patternInterface)
        {
            if (patternInterface == PatternInterface.Invoke)
            {
                returnthis;
            }




            returnnull;
        }
    }

大功告成!开启“讲述人”模式来验证成果吧!


开发者交流群:53078485,期待您的加入!
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值