老周最近熱衷於講故事,接下來仍是講故事時間。react
有人問我:你上大學的時候,有加入過學生會嗎?讀大學有沒有必要加入學生會?面試
哎喲,這怎麼回答呢,從短時間來講,加入學生會有點用,至少能夠娛樂一下,運氣好的話,說不定能遇到紅顏知己,但這機率至關低。從長遠發展看嘛,是沒什麼用。老周當年讀了四年本科,在學生會混了四年,什麼名堂也沒混出來。json
一方面老周向來不求虛名,因此也沒去參選所謂的什麼部長、主席之類的,這些「官銜」聽起來很高大上,實際上很庸俗蠢。既然沒興趣,於是老周更不須要去搞那些見不得人的勾當,什麼勾當?你懂的。其次,老周沒感受到這些職務,對未來的職業生涯發展有什麼幫助,基本上屬於混日子罷了。windows
老周當初一上大學,本不想進什麼學生會天地會之類的,之因此進了,純屬意外,簡直太意外了,事情是這樣的。話說那天學生會招新,儘管老周的母校比較老舊,但校園裏仍是被各處擺攤招新的學兄學姐們弄得像大觀園似的,熱鬧很是。app
誰不知道,大觀園裏美女多,因而我宿舍的室友開始動心了,有兩我的鼓起勇氣,決定明天去面試。原本跟我沒什麼關係,誰想次日,又有一位室友感興趣了,他們索性商量全宿舍一塊兒出動。老周本不想去,就被他們硬拉着去。async
一夥漫無目的地隨處看,我覺得他們是去看美女的,原來他們還真的去面試了,走着走着,咱們進入了一個教室,裏面坐着幾位師兄和師姐。進去前要在門口登記,寫上我的信息,而後排隊面試(教室裏都沒幾我的,排什麼隊),我說我不是來面試的,是陪室友來玩玩的。聽我一說完,一位師兄叫我出去走廊外面等。ide
正當我往外走時,另外一位師兄又把我叫回來,說既然來了就面面試吧,沒事的。這時候我才知道,他們是要招書法高手的。老周雖不敢當什麼高手,但從小就握過幾年毛筆,不防耍耍。就這樣,老周就莫名其妙地進了學生會。字體
想來有趣,原本想進的,沒進;我本不想進的,反而進了。真是世事無常,禍福相依啊。ui
=========================================================spa
故事講完了,下面說正經話。
話說上一回,老周給大夥伴們介紹了win 10中Toast通知的新型模板,既包含有舊版本的兼容格式,也有用於通用平臺的「自適應」通知。前一文章中,老周主要介紹了XML文檔的基本格式,並演示了兩個例子。
今天,我們探討一下如何在Toast通知中使用交互命令,並經過交互命令激活應用程序。所謂交互命令,就是在Toast通知的界面上添加一些可讓用戶操做的元素,來與應用程序進行互動。這些交互元素主要有:
一、按鈕。用action元素來指定,用戶點擊按鈕後會激活應用程序,並把用戶所點擊的按鈕的參數做爲激活參數傳遞給應用程序。
二、輸入框。就是一個文本框,用戶能夠在裏面輸入文本。
三、選擇列表。相似於下拉列表框,用戶能夠在裏面選擇一個項。
這些交互元素都統一放到actions元素下面。
舉個例子,好比這樣:
<toast> <visual> <binding template="ToastGeneric"> <text>唱山歌</text> <text>一塊兒去唱山歌吧.</text> <image placement="appLogoOverride" src="c.png" /> </binding> </visual> <actions> <action content="報名" arguments="join" imageUri="jn.png" /> <action content="不去" arguments="cancel" /> </actions> </toast>
你們能夠想象一下這個Toast通知是什麼樣子的,如今不截圖給你看,待會兒我們作示例時再看。
首先,visual元素在前一篇爛文中講過,是描述toast通知的可視化部分,第一個text被視爲標題,因此顯示出來字體較大,第二個text做爲正文,顯示一行文本。image元素指定一個圖像,由於設置了placement="appLogoOverride",代表這個圖像會替換應用的默認圖標,顯示在通知的左上角。
接下來,重點關注actions元素,actions元素下面專門用來放置交互命令,有兩個元素可用:
<action>:表示定義一個命令按鈕。例如:
<action content = "肯定" arguments = "yes" activationType ="foreground或background" imageUrl="b.png" />
content表示要在按鈕上顯示的文本,上面例子在按鈕上顯示「肯定」。imageUrl表示顯示在按鈕上的圖標,若是不用圖標,就能夠不設置imageUrl屬性。arguments用來指定一個參數,這個參數是你本身定的,好比我這裏叫yes,當用戶點擊按鈕後,arguments的值會傳遞給應用程序,這樣應用程序纔會知道你到底點擊了哪一個按鈕。
activationType指示以何種方式激活應用程序,若是值爲foreground,則代表toast通知將在前臺激活應用程序,這時候用戶能夠看見應用程序;若是值爲background,代表toast通知經過後臺方式激活應用,此時用戶看不到應用程序,後臺激活必須指定一個後臺任務,當激活時就會執行後臺任務。若是值爲protocol,表示將經過協議來激活應用程序。
若是但願用戶能夠在Toast通知上輸入內容,能夠這樣定義XML:
<input id="name" type="text" />
Toast通知上會顯示一個文本框,id屬性是必須指定的,並且必須是actions中的惟一值,不能重複,這個id值在激活應用程序時會傳遞給應用。type屬性指定input元素的類型,text表示文本框,讓用戶輸入文本。若是是selection表示顯示一個列表選擇框,用戶只能從中選擇一個項。
若是type爲selection,那麼input元素下會包含N個selection元素,每一個selection元素表示一個選項,如
<input id="age" type="selection"> <selection content="五歲" id="5" /> <selection content="七歲" id="7" /> </input>
上面例子,定義了兩個選項,每一個selection的id值必須惟一,它表示該項的值,這個id也會傳遞給被激活的程序。content表示項中顯示的文本,用來給你看的。即當toast彈出時,在下拉列表中,你看到的是五歲、七歲兩個選項。
下面咱們來實戰一下,先看Toast通知如何從前臺激活應用。
首先構造XML文檔。
string visual = "<visual>" + "<binding template=\"ToastGeneric\">" + "<text>宇宙第一應用</text>" + "<text>應用正在收集您的信息。</text>" + "</binding>" + "</visual>"; string actions = "<actions>" + "<input id=\"name\" type=\"text\" placeHolderContent=\"請輸入姓名\" />" + "<input id=\"city\" type=\"text\" placeHolderContent=\"請輸入城市\" />" + "<action content=\"肯定\" arguments=\"ok\" />" + "<action content=\"取消\" arguments=\"cancel\" activationType=\"foreground\" />" + "</actions>"; string toastXml = $"<toast>{visual}{actions}</toast>";
有一點大夥要注意,當input和action元素同時使用時,input元素必須放在action元素的前面。placeHolderContent屬性主要設置佔位文本,即當文本框中沒有輸入任何內容時顯示的文本。
上面的Toast通知定義了兩個可供輸入的文本框,以及兩個命令按鈕。
下面代碼顯示通知。
// 加載XML文檔 XmlDocument doc = new XmlDocument(); doc.LoadXml(toastXml); // 顯示通知 ToastNotification notification = new ToastNotification(doc); ToastNotifier notifier = ToastNotificationManager.CreateToastNotifier(); notifier.Show(notification);
正由於應用程序是被前臺激活的,因此確定要爲Application類做激活處理,在App類中,重寫基類的OnActivated方法。
protected override void OnActivated(IActivatedEventArgs args) { // 判斷激活類型 // 確認是由Toast通知激活應用 if (args.Kind == ActivationKind.ToastNotification) { // 轉換參數類型 ToastNotificationActivatedEventArgs toastargs = (ToastNotificationActivatedEventArgs)args; // 獲取頁面引用 Frame root = Window.Current.Content as Frame; if (root == null) { root = new Frame(); Window.Current.Content = root; } if (root.Content == null) { root.Navigate(typeof(MainPage)); } MainPage page = (MainPage)root.Content; // 判斷用戶點擊哪一個按鈕 string activeargs = toastargs.Argument; if (activeargs == "ok") //肯定按鈕 { // 獲取用戶輸入的內容 string name = toastargs.UserInput["name"] as string; string city = toastargs.UserInput["city"] as string; page.ShowTextFromForeactivation($"用戶點擊了肯定按鈕,輸入的內容爲:\n姓名:{name}\n城市:{city}。"); } else //取消按鈕 { page.ShowTextFromForeactivation("用戶點擊了取消按鈕。"); } } Window.Current.Activate(); }
先要經過方法參數的Kind屬性來判斷一下應用程序是否是被Toast通知所激活的,若是值是ToastNotification,證實應用程序是被Toast通知激活的。
而後要把方法參數的類型轉化爲ToastNotificationActivatedEventArgs類型,ToastNotificationActivatedEventArgs類專用於Toast通知的激活。
Argument屬性中取得的值就是被點擊的action的arguments屬性中的值,上面我定義的toast有兩個action,arguments的值分別爲ok和cancel,若是用戶點擊了肯定按鈕,那麼從ToastNotificationActivatedEventArgs對象的Argument屬性獲得的值爲ok,不然就是cancel。
UserInput屬性獲取的就是input元素的值,屬性類型爲ValueSet,其實是一個字典類型。Key爲Toast通知中input元素的id,Value的值是input元素中輸入的內容。經過UserInput屬性,程序就知道用戶在文本框中輸入了什麼內容。
運行應用程序,當通知彈出時,輸入相關內容,以下圖。
輸入一些文本後,而後點擊肯定按鈕,而後應用程序被激活,會看到主頁面上顯示從Toast通知傳遞到應用程序的輸入數據。以下圖所示。
---------------------------------------------------------------------------------------------------
上面演示的是Toast通知從前臺激活應用程序,下面來看看後臺激活。Toast通知從後臺激活應用程序,用戶不會看到應用程序界面,但應用程序會在後臺任務中處理從Toast通知傳遞到應用程序的數據。
要實現從後臺處理Toast通知,首先要實現一個後臺任務。記住後臺任務要在一個獨立的Runtime組件項目中。後臺的實現代碼以下:
public sealed class ToastBgTask : IBackgroundTask { public async void Run(IBackgroundTaskInstance taskInstance) { var deferral = taskInstance.GetDeferral(); ToastNotificationActionTriggerDetail details = taskInstance.TriggerDetails as ToastNotificationActionTriggerDetail; if (details != null) { // 先確認用戶點擊了yes按鈕 string cmdargs = details.Argument; if (cmdargs == "yes") { // 獲取選擇的項 object value = details.UserInput["ut"]; // 保存數據 StorageFolder local = ApplicationData.Current.LocalFolder; JsonObject jsobj = new JsonObject(); jsobj.SetNamedValue("updatetime", JsonValue.CreateNumberValue(Convert.ToDouble(value))); StorageFile newFile = await local.CreateFileAsync("data.json", CreationCollisionOption.ReplaceExisting); await FileIO.WriteTextAsync(newFile, jsobj.Stringify(), Windows.Storage.Streams.UnicodeEncoding.Utf8); } } deferral.Complete(); } }
當Toast通知激活後臺任務後,能夠從 taskInstance.TriggerDetails屬性獲取到一個ToastNotificationActionTriggerDetail對象實例。和前臺激活同樣,經過Argument屬性能夠獲取Toast通知中被用戶點擊的action元素的參數。從UserInput屬性能夠獲取到input元素的id值。
後臺任務完成後,記得要在主項目中引用,這個老周已經重複了幾千遍了。
而後打開清單文件,在Package/Applications/Application節點下添加後臺任務聲明。
<Extensions> <Extension Category="windows.backgroundTasks" EntryPoint="BackgroundTasks.ToastBgTask"> <BackgroundTasks> <Task Type="general"/> </BackgroundTasks> </Extension> <
/Extensions>
因爲在後臺任務中,是把用戶在Toast通知上選擇的項保存到本地文件中,因此在主應用中,能夠讀出文件的內容,並顯示出來。
protected override async void OnNavigatedTo(NavigationEventArgs e) { try { // 讀入後臺保存的內容 StorageFolder local = ApplicationData.Current.LocalFolder; StorageFile dataFile = await local.GetFileAsync("data.json"); if (dataFile == null) return; string jsstr = await FileIO.ReadTextAsync(dataFile, Windows.Storage.Streams.UnicodeEncoding.Utf8); JsonObject jsobj = null; if (JsonObject.TryParse(jsstr, out jsobj)) { double d = jsobj.GetNamedNumber("updatetime"); tbResultFromBackActivate.Text = $"你選擇了每隔{d:N0}天更新一次。"; } await dataFile.DeleteAsync(); } catch(Exception ex) { Debug.WriteLine($"文件讀取異常:{ex.Message},異常類型:{ex.GetType().Name}。"); } }
最後,咱們實現顯示Toast通知的代碼。
string visual = "<visual>" + "<binding template=\"ToastGeneric\">" + "<text>無敵應用</text>" + "<text>請選擇更新間隔天數。</text>" + "</binding>" + "</visual>"; string actions = "<actions>" + "<input id=\"ut\" type=\"selection\" defaultInput=\"5\">"+ "<selection id=\"3\" content=\"3天\" />" + "<selection id=\"5\" content=\"5天\" />" + "<selection id=\"10\" content=\"10天\" />" + "</input>" + "<action content=\"是\" activationType=\"background\" arguments=\"yes\" />" + "<action content=\"否\" activationType=\"background\" arguments=\"no\" />" + "</actions>"; string toastXml = $"<toast>{visual}{actions}</toast>"; XmlDocument doc = new XmlDocument(); doc.LoadXml(toastXml); ToastNotification notification = new ToastNotification(doc); ToastNotifier notifier = ToastNotificationManager.CreateToastNotifier(); notifier.Show(notification);
input元素的type爲selection,表示Toast通知上的輸入行爲爲列表選擇,並使用三個selection元素定義了三個選項。注意,在input元素中,defaultInput屬性指定輸入控件的默認值。若是type爲text,該屬性設置默認的文本;在本例中,type爲selection,因此默認值就是但願默認被選中的項的id值。
彷佛一切就緒了,實際上咱們還有很關鍵一步沒有作——註冊後臺任務,清單文件中僅僅是聲明,而要但願讓Toast通知的操做激活後臺任務,還須要對後臺任務進行註冊。
private async void RegToastBackgroundTask() { // 判斷一下是否容許訪問後臺任務 var res = await BackgroundExecutionManager.RequestAccessAsync(); if (res == BackgroundAccessStatus.Denied || res == BackgroundAccessStatus.Unspecified) { return; } Type taskType = typeof(BackgroundTasks.ToastBgTask); var task = BackgroundTaskRegistration.AllTasks.Values.FirstOrDefault(t => t.Name == taskType.Name); if (task == null) { // 註冊後臺任務 BackgroundTaskBuilder bd = new BackgroundTaskBuilder(); bd.Name = taskType.Name; bd.TaskEntryPoint = taskType.FullName; // 聲明觸發器 ToastNotificationActionTrigger trigger = new ToastNotificationActionTrigger(); bd.SetTrigger(trigger); task = bd.Register(); } }
後臺的觸發器便用 ToastNotificationActionTrigger類型。
如今咱們來看一下,運行程序,等Toast通知出現後,把程序關了。而後在Toast通知上選擇一個項,而後提交。
而後再次啓動應用程序,能夠看到結果了。
如何,這Win10的Toast通知是否是很牛X呢。因爲小妹妹正在拿着個人920玩,因此就不用手機運行了,手機模擬器沒有安裝,大夥兒有興趣的能夠耍耍。
示例源碼:http://files.cnblogs.com/files/tcjiaan/toastActivationApp.zip