UWP开发砸手机系列(二)—— “讲述人”识别自定义控件Command
上一篇我们提到如何让“讲述人”读出自定义的CanReadGrid,但“讲述人”仍然无法识别CanReadGrid上绑定的Command。XAML代码如下:
<StackPanel>
<TextBlock Text="{x:Bind Title,Mode=OneWay}" Foreground="White"></TextBlock>
<local:CanReadGrid Background="Red" AutomationProperties.Name="Can read gird" Height="100">
<Interactivity:Interaction.Behaviors>
<Core:EventTriggerBehavior EventName="Tapped">
<Core:InvokeCommandAction Command="{x:Bind ChangeTitleCommand}"/>
</Core:EventTriggerBehavior>
</Interactivity:Interaction.Behaviors>
</local:CanReadGrid>
</StackPanel>
我们可以看到通过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的依赖属性(Dependency Property):
public System.Windows.Input.ICommand Command { get; set; }
Member of Windows.UI.Xaml.Controls.Primitives.ButtonBase
而我们自定义的CanReadGrid,则是通过附加属性(Attached Property)来获得绑定Command的能力。
附件属性也是一种特殊的依赖属性,二者殊归同路。既然Button通过依赖属性可以做到的事情,附加属性一样可以完成。
想要弄明白Button的Command是如何被调用的,最简单的办法就是去查看源码呗:
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>
protected override string 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>
protected override 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>
public override object GetPattern(PatternInterface patternInterface)
{
if (patternInterface == PatternInterface.Invoke)
{
return this;
}
return base.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())
{
throw new ElementNotEnabledException();
}
base.Dispatcher.BeginInvoke(DispatcherPriority.Input, new DispatcherOperationCallback(delegate(object param)
{
((Button)base.Owner).AutomationButtonBaseClick();
return null;
}), null);
}
}
果不其然发现了上一篇我们提到的GetClassNameCore,GetAutomationControlTypeCore,GetPattern三个方法。另外还有一个奇怪的void IInvokeProvider.Invoke()。这货看名字也能猜出来是干啥的啦,这货竟然去调了Button类里的Click方法……
知道真相的我眼泪流出来……搞啥呢,那我在这里调一下Command.Execute不就成了!
首先我们给CanReadGrid添加ExecuteCommand方法,该方法通过DependencyObject的GetValue方法一层层拿到Command,然后执行Execute。
public class CanReadGrid : Grid
{
protected override AutomationPeer OnCreateAutomationPeer()
{
return new GridAutomationPeer((this));
} public void ExecuteCommand()
{
var behaviors = Interaction.GetBehaviors(this);
var actions = behaviors[].GetValue(EventTriggerBehavior.ActionsProperty) as ActionCollection;
var command = actions[].GetValue(InvokeCommandAction.CommandProperty) as ICommand;
command.Execute(null);
}
}
第二步就是完善GridAutomatioPeer,这里需要注意的是IInvokeProvider这个接口,通过Button的源码推测具有Action的控件需要实现这个接口的Invoke方法来执行操作。我们也是在Invoke方法里来调用CanReadGrid类里的ExecuteCommand方法。
public class GridAutomationPeer : FrameworkElementAutomationPeer, IInvokeProvider
{
public GridAutomationPeer(Grid owner)
: base(owner)
{ } public async void Invoke()
{
await CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal,
() =>
{
((CanReadGrid)base.Owner).ExecuteCommand();
});
} protected override object GetPatternCore(PatternInterface patternInterface)
{
if (patternInterface == PatternInterface.Invoke)
{
return this;
} return null;
}
}
大功告成!开启“讲述人”模式来验证成果吧!
结尾插播个广告,本篇内容100%原创,当时俺翻烂了Google的搜索页面、中英文各种blog也木有讲如何让“讲述人”调用Command,逼的俺自由发挥啊。特地写了这篇造福全人类,各位不要吝啬点个推荐哦,虽然“讲述人”并没有什么卵用……
UWP开发砸手机系列(二)—— “讲述人”识别自定义控件Command的更多相关文章
- UWP开发砸手机系列(一)—— Accessibility
因为今天讨论的内容不属于入门系列,所以我把标题都改了.这个啥Accessibility说实话属于及其蛋疼的内容,即如何让视力有障碍的人也能通过声音来使用触屏手机……也许你这辈子也不会接触,但如果有一天 ...
- 使用 PySide2 开发 Maya 插件系列二:继承 uic 转换出来的 py 文件中的类 Ui_Form
使用 PySide2 开发 Maya 插件系列二:继承 uic 转换出来的 py 文件中的类 Ui_Form 开发环境: Wing IDE 6.1 步骤1: 打开 Wing IDE,创建一个新的 pr ...
- MUI框架开发HTML5手机APP(二)--页面跳转传值&底部选项卡切换
概 述 JRedu 在上一篇博客中,我们学习了如何使用Hbuilder创建一个APP,同时如何使用MUI搭建属于自己的第一款APP,没有学习的同学可以戳链接学习: http://www.cnblo ...
- [UWP开发]处理手机后退事件
众所周知,uwp程序是一套代码,可以run在不同的平台上.但是不同的设备肯定有其独特之处,所以针对这些独特之处,必须用“独特的代码”来处理. 所以微软提供了一系列的拓展类库来实现这种特殊处理. 如上图 ...
- Win10 UWP开发:摄像头扫描二维码/一维码功能
这个示例演示整合了Aran和微软的示例,无需修改即可运行. 支持识别,二维码/一维码,需要在包清单管理器勾选摄像头权限. 首先右键项目引用,打开Nuget包管理器搜索安装:ZXing.Net.Mobi ...
- UWP开发入门(十二)——神器Live Visual Tree
很久以前,我们就有Snoop这样的工具实时修改.查看正在运行的WPF程序,那时候调个样式,修改个模板,相当滋润.随着历史的车轮陷进WP的泥潭中,无论WP7的Silverlight还是WP8.1的run ...
- 步步为营 SharePoint 开发学习笔记系列总结
转:http://www.cnblogs.com/springyangwc/archive/2011/08/03/2126763.html 概要 为时20多天的sharepoint开发学习笔记系列终于 ...
- 使用 PySide2 开发 Maya 插件系列 总览
使用 PySide2 开发 Maya 插件系列 总览 使用 PySide2 开发 Maya 插件系列一:QT Designer 设计GUI, pyside-uic 把 .ui 文件转为 .py 文件 ...
- 【Qt编程】基于Qt的词典开发系列<十二>调用讲述人
我们知道,win7系统自带有讲述人,即可以机器读出当前内容,具体可以将电脑锁定,然后点击左下角的按钮即可.之前在用Matlab写扫雷游戏的时候,也曾经调用过讲述人来进行游戏的语音提示.具体的Matla ...
随机推荐
- Android 多线程注意事项
参考:http://blog.csdn.net/x86android/article/details/14161981 http://geeksun.iteye.com/blog/1447708 An ...
- 项目管理工具maven(二)
2 整合ssh框架 2.1 依赖传递 只添加了一个struts2-core依赖,发现项目中出现了很多jar, 这种情况 叫 依赖传递 2.2 依赖版本冲突的解决 1. 第一声明优先原则 <dep ...
- VB.NET条码机打印设置纸张大小的方法
Imports System.Drawing.PrintingImports System.Runtime.InteropServices Public Class Page <Runti ...
- 常见反编译产生错误 k__BackingField 解决办法
常见反编译产生错误 k__BackingField 解决办法 无聊反编译小蚂蚁出现上千的错同样的错 private bool <EnableRuntimeHandler> ...
- MySQL备份恢复全实战
一. 简介 1. 增量备份 增量备份是指在一次全备份或上一次增量备份后,以后每次的备份只需备份与前一次相比增加或者被修改的文件.这就意味着,第一次增量 备份的对象是进行全备后所产生的增加和修改的文件; ...
- ACM Dance Recital(dfs+剪枝)
The Production Manager of a dance company has been tasked with determining the cost for the seasonal ...
- “MSDTC 事务的导入失败: Result Code = 0x8004d00e。
今天搞数据库移植,也把分布式程序移植了一下,一直报上面的错误,差点要重装了 %>_<%,网上看了几篇文章偶然间用DPCPING工具测试了下连接,发现不行.想到host文件的配置,发现其中 ...
- 关于进程exit后,内存释放释放的实践
最近碰到一个问题,或许也是小猿们都会碰到的问题:内存泄露. 都知道malloc后需要free才能释放内存,shmat后需要shmdt才能断掉内存区并使用IPC_RMID命令删除共享内存.那么如果是当前 ...
- cudnn 安装
ubuntu 下载地址 https://developer.nvidia.com/rdp/cudnn-download 安装教程 http://docs.nvidia.com/deeplearning ...
- Yosemite 给 iOS 录屏
[Yosemite 给 iOS 录屏] Mac 升级到Yosemite后,支持iOS屏幕录制.把Mac和iPhone用数据线相连.打开QuickTime Player,新建一个影片. 从摄像头源中选择 ...