因為今天討論的內容不屬於入門系列,所以我把標題都改了。這個啥Accessibility說實話屬於及其蛋疼的內容,即如何讓視力有障礙的人也能通過聲音來使用觸屏手機……也許你這輩子也不會接觸,但如果有一天你遇到了,碰巧你又看了我這一篇,你就可以挺起胸膛大聲說:這個逼我裝定了!
首先我們來看下Accessibility在Windows 10 Mobile上原生支持的情況,點擊“設置”-》“輕松使用”-》“講述人”,開啟講述人之后,你可以先體驗個幾分鍾(另外講述人對中文的支持並不是很好,建議切換到英文系統)。
我知道你想砸手機,但先別急着,等我們把今天的內容講完再砸……
如何實現讓“講述人”朗讀屏幕內容呢?按照某軟一貫的尿性,HelloWorld必然簡單到讓人發指,只需給想要被朗讀的控件添加“AutomationProperties.Name”就可以了。
<Button AutomationProperties.Name="I am a button">Button</Button>
手指戳上去的時候就會聽到“I am a button”。如果你做完了這個Sample然后就跑去匯報可行性,那你就完了……
首先我們遇到的第一個問題就是講述人無法識別自定義的控件,甚至連Grid,Border這樣的默認沒有交互的控件也不會識別,這個是很糟糕的。項目中難免會用到一些UserControl、CustomControl的,DataTemplate里又總會用到Grid啥的。這里統統讀不出來,作為一個負責任的大公司,產品就不能發布了,后果很嚴重。
如何解決這個問題呢?其實也沒那么復雜啦,某軟還是提供了一些接口來做這些事情,參考了MSDN上的文檔(極其沒有卵用)和給出的Sample(有誤導人的嫌疑),最終又查看了Silverlight里Button和TextBlock的源碼(Windows Runtime貌似沒有可以反編譯的工具可以看到源碼,ILSpy和JustDecompile均只能看到接口定義)。給出以下的解決方案:
解決方案以Grid舉例,意圖讓“講述人”識別Grid並念出AutomationProperties.Name中填寫的文本。
public class CanReadGrid : Grid { protected override AutomationPeer OnCreateAutomationPeer() { return new GridAutomationPeer(); } } public class GridAutomationPeer : AutomationPeer { protected override object GetPatternCore(PatternInterface patternInterface) { if (patternInterface == PatternInterface.Grid) { return this; } return null; } protected override AutomationControlType GetAutomationControlTypeCore() { return AutomationControlType.Custom; } protected override string GetClassNameCore() { return "CanReadGrid"; } }
第一步需要繼承自現有的系統控件Gird,然后override方法OnCreateAutomationPeer,該方法繼承自UIElement,已經是非常底層的對象了。但如果你去查看Grid類本身的接口定義,會發現Grid是沒有對該方法做處理的。而默認就可以讀出的Button和TextBlock等控件均override了該方法。
// // Summary: // 在派生類中實現時,為 Microsoft UI 自動化基礎結構返回類特定的 AutomationPeer 實現。 // // Returns: // 要返回的類特定的 AutomationPeer 子類。 protected virtual AutomationPeer OnCreateAutomationPeer();
第二步需要創建類GridAutomationPeer繼承自AutomationPeer。AutomationPeer文檔中給出的說法是“提供一個對 Microsoft
UI 自動化公開關聯所有者類的自動化同級的基類”。(雖然高考語文還可以,但仍不足以正確閱讀理解MSDN天書……)既然文檔看不懂,干脆就直接抄襲Button和TextBlock的源碼來寫唄。經反復比較推敲,確認了最為核心的方法protected override object GetPatternCore(PatternInterface
patternInterface),親測鑒定只要實現了該方法,即可由講述人識別。GetAutomationControlTypeCore和GetClassNameCore都只是錦上添花而已。最終使用的XAML如下:
<local:CanReadGrid Background="Red" AutomationProperties.Name="Can read gird"> </local:CanReadGrid>
這個自定義的Grid終於能被“講述人”毫無感情的念出“can read gird”了。說實話還是Contana的聲音好聽一些。
本篇介紹了如何讓講述人念出自定義控件,並強力建議先不要砸手機或匯報可行性分析,因為我還留了一個大坑給你們。可交互的控件比如Button,講述人會語音提示雙擊可以激活Click操作,通過ViewModel中的Command綁定也沒有問題。但問題是沒有Command屬性的控件要如何處理?通過Behaviors綁定的Command是萬萬不可能會自動識別的啦?想要知道答案的,下個禮拜見……
