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 ...
随机推荐
- Python 中 logging 日志模块在多进程环境下的使用
因为我的个人网站 restran.net 已经启用,博客园的内容已经不再更新.请访问我的个人网站获取这篇文章的最新内容,Python 中 logging 日志模块在多进程环境下的使用 使用 Pytho ...
- jQuery deferred.resolve() 方法
jQuery deferred.resolve() 方法 deferred.resolve() 函数用于解决Deferred(延迟)对象,并根据给定的args参数调用任何 doneCallbacks ...
- 模板引擎 引自 《PHP核心技术与最佳实践》
随着web的发展,仅一门语言或者一种技术已经不能满足需求,分层架构显得越来越重要.在大型架构中,从来不会简单地应用php从头到尾实现一个完整的mvc架构.可能底层是c/java的支撑,负责密集运算和y ...
- mysql 塞数据
./mysql_.py -H109.105.4.65 -P32773 -uroot -proot.123 --database=test_database --number=10 sysbench - ...
- nasm 与 masm语法区别
看到一篇文章,是介绍nasm语法的:http://blog.csdn.net/hitop0609/article/details/4329454 masm是微软专门为windows下汇编而写的,而na ...
- 286被围绕的区域 · Surrounded Regions
[抄题]: 给一个二维的矩阵,包含 'X' 和 'O', 找到所有被 'X' 围绕的区域,并用 'X' 填充满. 样例 给出二维矩阵: X X X X X O O X X X O X X O X X ...
- Oracle ADF VO排序及VO的查询模式
常规应用中,当需要使用Table向终端用户展示数据时,Table中数据的显示排序一致性极大程度的影响到了客户体验.通常希望诸如多次查询结果显示顺序相同.插入数据在原数据上方等的实现. ADF为开发人员 ...
- C语言命令行处理
一.简介 getopt()函数是一个标准库调用,可允许您使用直接的 while/switch 语句方便地逐个处理命令行参数和检测选项(带或不带附加的参数).与其类似的getopt_long()允许在几 ...
- Java程序设计19——类的加载和反射-Part-B
接下来可以随意提供一个简单的主类,该主类无须编译就可使用上面的CompileClassLoader来运行它. package chapter18; public class Hello { publi ...
- 修改数据库中的内容报错:PropertyAccessException:Null value was assinged to a property of primitive type setter of
错误原因:totalTime的类型为int,数据库中为NULL,int 类型不能赋值为NULL,只能为0,所以报此异常. 解决方案:将totalTime的类型改为Integer,或者初始化为0