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

Cle****-he UID.1073626
2016-01-07 发表

本帖最后由 Clever-he 于 2016-1-7 10:28 编辑

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

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

[mw_shl_code=csharp,true]<Button Command="{x:Bind ChangeTitleCommand}">I am Button</Button>[/mw_shl_code]

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

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

[mw_shl_code=csharp,true]public System.Windows.Input.ICommand Command { get; set; }
Member of Windows.UI.Xaml.Controls.Primitives.ButtonBase[/mw_shl_code]

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

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

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

[mw_shl_code=csharp,true]public class 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);
}
}[/mw_shl_code]

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

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

[mw_shl_code=csharp,true]public class 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);
}
}
[/mw_shl_code]

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

[mw_shl_code=csharp,true]public class 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;
}
}
[/mw_shl_code]

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

开发者交流群:53078485,期待您的加入!

敬告:
为防止不可控的内容风险,本站已关闭新用户注册,新贴的发表及评论;
你现在看到的内容只是互联网用户曾经发表的言论快照,仅用于老用户留存纪念,且仅与科技行业相关,全部内容不代表本站观点及立场;
本站重新开放前已针对包括用户隐私、版权保护、信息安全、国家政策在内的各种互联网法律法规要求,执行了隐患内容的自查、屏蔽和删除;
本站目前所属个人主体,未有任何盈利安排与计划,且与原WFUN.COM所属公司不存在任何关联关系;
如果本帖内容或者相关资源侵犯到您的合法权益,或者您认为存在问题,那么请您务必点此举报或投诉!
全部回复:
xllk UID.1003933
2016-01-07 使用 Lumia 920 回复

看不懂,但留名

DummVan UID.145740
2016-01-07 回复

不明觉厉。。

本站使用Golang构建,点击此处申请开源鄂ICP备18029942号-4联系站长投诉/举报