免責聲明:本文章由fengyun1989創作,採用知識共享署名-非商業性使用-相同方式共享 2.5 中國大陸許可協議進行許可。
到這裏,我們已經擁有一個不錯的程序,可以數據的增刪改,可以看到當前的課表內容等。接下來,我們要實現Snapped模式,用磁貼來實現數據的顯示,還有徽章(badge)的運用。
什麼是Snapped模式呢,就是程序的分屏顯示,Windows 8 Snap 要求至少 1366 * 768 的顯示分辨率才能使用,其實程序本身就能夠Snapped,只是顯示效果不盡然如我們所願。我們的目標就是實現按照我們的意願的snapped模式。
那麼怎麼在模擬器啓動snapped模式呢,使用手指模式,然後再模擬器屏幕上方,向中間劃,就能看到程序變成縮略圖,然後就向左或向右滑動就能進入snapped模式了。如下圖:
如果不能看到,那麼請修改模擬器的分辨率,點擊右側工具欄的小電腦按鈕,選擇1366 * 768以上的分辨率。
看上圖的顯示效果,看起來不太友好,雖然基本信息也出來了。那麼我們可以用代碼捕捉到程序的改變,然後進行佈局調整。
在MainPage的構造函數裏面註冊這麼一個事件:
Window.Current.SizeChanged += Current_SizeChanged;
這個事件可以在程序顯示大小改變的時候觸發。另外,給MainPage的Grid設置一個Name的屬性:
<Grid x:Name="GridLayout" Background="{StaticResource AppBackgroundColor}">
然後修改Current_SizeChanged方法如下:
void Current_SizeChanged(object sender, Windows.UI.Core.WindowSizeChangedEventArgs e)
{
var currentViewState = Windows.UI.ViewManagement.ApplicationView.Value;
if (currentViewState == ApplicationViewState.Snapped)
{
GridLayout.ColumnDefinitions[0].Width = new GridLength(e.Size.Width * 0.6);
WeekdayListTitle.FontSize = 24;
ItemDetailTitle.FontSize = 24;
}
else
{
GridLayout.ColumnDefinitions[0].Width = new GridLength(e.Size.Width / 2);
WeekdayListTitle.FontSize = 56;
ItemDetailTitle.FontSize = 56;
}
}
上面改變的時候就改變視圖。Windows.UI.ViewManagement.ApplicationView有一個TryUnsnap方法,可以使snapped模式恢復爲正常的全屏視圖。
現在,我們的視圖變成好看多了吧。當然,可以在XAML裏面定義好VisualStateManager,在後臺代碼稍加控制state,也能達到效果。
這裏提供微軟的例子地址:http://code.msdn.microsoft.com/windowsapps/Snap-Sample-2dc21ee3
磁貼和徽章(Badge)
靜態磁貼需要的是三種規模的圖片。30*30,150*150,310*150三種像素的圖片。如果大家沒有這種大小的圖片,請到這裏下載:http://dl.dbank.com/c0ak8gdsuc
我把圖片都放在了Assets文件夾,現在打開Package.appxmanifest,修改如下:
這樣,如上圖所示修改,編譯運行就能看到結果了。在模擬器怎麼實現寬磁貼變爲小磁貼呢,按緊磁貼,稍微向下拖動,就能看到會有Appbar彈出,就能改變磁貼了。
在Package.appxmanifest裏面有很多關於程序的設置,大家可以看下。
動態磁貼
磁貼的動態更新都要基於模板,模板都是一些微軟定義好的枚舉類型。詳請看http://msdn.microsoft.com/en-us/library/windows/apps/hh761491.aspx。
模板系統是基於XML片段,比如下面這段模板:
<tile>
<visual lang="en-US">
<binding template="TileSquareText03">
<text id="1">Text Field 1</text>
<text id="2">Text Field 2</text>
<text id="3">Text Field 3</text>
<text id="4">Text Field 4</text>
</binding>
</visual>
</tile>
只有4行,我們就利用填充Xml的方式並傳遞給系統來更新磁貼。爲了從所以數據中獲取我們需要更新到磁貼的數據,我寫了這麼些方法添加到MainPage。算法簡陋,勿見怪。
ScheduleItem GetNowSchedule()
{
DateTime date = DateTime.Now;
string weekday = date.DayOfWeek.ToString();
string localWeekday = GetLocalWeekday(weekday);
var weekdayList = viewModel.WeekdayList;
int index = 0;
for (int i = 0; i < weekdayList.Count; i++)
{
if (weekdayList[i].Weekday == weekday || weekdayList[i].Weekday == localWeekday)
{
index = i;
break;
}
}
List<DateTime> scheduleStartTime = new List<DateTime>();
for (int i = 0; i < weekdayList[index].ScheduleList.Count; i++)
{
ScheduleItem item = weekdayList[index].ScheduleList[i];
string[] times = item.StartTime.Split(':');
int hour = Convert.ToInt32(times[0]);
int minute = Convert.ToInt32(times[1]);
DateTime tempDate = new DateTime(date.Year, date.Month, date.Day, hour, minute, 0);
scheduleStartTime.Add(tempDate);
}
TimeSpan MinDate;
int scheduleIndex = 0;
for (int i = 0; i < scheduleStartTime.Count; i++)
{
if ((scheduleStartTime[i] - date).Hours >= 0)
{
if (scheduleIndex == 0)
{
MinDate = scheduleStartTime[i] - date;
scheduleIndex = i;
}
else
{
if (MinDate > (scheduleStartTime[i] - date))
{
scheduleIndex = i;
MinDate = scheduleStartTime[i] - date;
}
}
}
}
return weekdayList[index].ScheduleList[scheduleIndex];
}
string GetLocalWeekday(string weekday)
{
string returnValue = String.Empty; ;
switch (weekday)
{
case "Moonday": returnValue = "星期一"; break;
case "Tuesday": returnValue = "星期二"; break;
case "Wednesday": returnValue = "星期三"; break;
case "Thursday": returnValue = "星期四"; break;
case "Friday": returnValue = "星期五"; break;
case "Saturday": returnValue = "星期六"; break;
case "Sunday": returnValue = "星期日"; break;
default:
break;
}
return returnValue;
}
上面做的是取出下一個即將需要上的課。判斷方法有點麻煩,算法不太好。主要是重複遍歷。先獲取當天在weekdayList的index。然後再通過時間來判斷哪個是最接近當前時間的。算法有點問題,如果過了當天上課的時間,不能顯示下一天的第一節課的時間。這個作爲示例程序就這樣吧。大家可以通過改變系統的時間來達到測試的目的。
既然能夠獲取數據了,下面進行磁貼更新,添加這麼一個方法到MainPage:
void UpdateTile()
{
ScheduleItem showScheduleItem = GetNowSchedule();
XmlDocument tileXml = TileUpdateManager.GetTemplateContent(TileTemplateType.TileSquareText03);
XmlNodeList textNodes = tileXml.GetElementsByTagName("text");
textNodes[0].InnerText = showScheduleItem.LessonName;
textNodes[1].InnerText = showScheduleItem.ClassRoom;
textNodes[2].InnerText = showScheduleItem.StartTime + "-" + showScheduleItem.EndTime;
for (int i = 0; i < 5; i++)
{
TileUpdateManager.CreateTileUpdaterForApplication().Update(new TileNotification(tileXml));
}
}
上面的代碼,先獲取模板,然後對模板進行填充,最後一個for循環通知系統更新磁貼,循環5次是爲了保證磁貼更新能夠正確處理。所以5次操作。
現在在構造函數添加這麼一行:
UpdateTile();
那麼,這次要在本地計算機上調試,鑑於數據的重複性,我設置時間到了星期一的中午,因爲星期一的三個課程都不一樣。
可能很難立即獲得更新後瓷磚。你可以從以下獲得幫助:
- 關閉模擬器
- 重啓visual studio
- 在開始菜單卸載另一個(沒有關係)應用
- 尋找使用開始開始菜單的MetroGrocer應用。
- 在開始菜單移動一些其他的瓷磚
- 重啓電腦
- 清理工程再重新生成
我這次就是清理工程後重新生成纔行。不過,一旦獲取更新,以後就不會再次消失。
但是現在寬磁貼的更新好沒有做。現在在磁貼上右鍵--放大,就會發現什麼數據都沒有。
更新寬磁貼
要更新兩個瓷磚尺寸(方的和寬的),你需要將兩個XML模板來創建一個單一的片段,其中包含兩個更新。寬模板相對於普通的模板有幾個額外的字段,
<tile>
<visual lang="en-US">
<binding template="TileSquareText03">
<text id="1">Apples</text>
<text id="2">Hotdogs</text>
<text id="3">Soda</text>
<text id="4"></text>
</binding>
<binding template="TileWideBlockAndText01">
<text id="1">Apples (Whole Foods)</text>
<text id="2">Hotdogs (Costco)</text>
<text id="3">Soda (Costco)</text>
<text id="4"></text>
<text id="5">2</text>
<text id="6">Stores</text>
</binding>
</visual>
</tile>
沒有組合模版的API。我採用的方法是使用XML處理來支持分開填充模板,然後在過程的最後將它們組合,註釋掉原來的UpdateTile方法,然後添加新的UpdateTile方法
void UpdateTile()
{
ScheduleItem showScheduleItem = GetNowSchedule();
XmlDocument narrowTileXml = TileUpdateManager.GetTemplateContent(TileTemplateType.TileSquareText03);
XmlDocument wideTileXml = TileUpdateManager.GetTemplateContent(TileTemplateType.TileWideBlockAndText01);
XmlNodeList narrowTextNodes = narrowTileXml.GetElementsByTagName("text");
XmlNodeList wideTextNodes = wideTileXml.GetElementsByTagName("text");
narrowTextNodes[0].InnerText = showScheduleItem.LessonName;
narrowTextNodes[1].InnerText = showScheduleItem.ClassRoom;
narrowTextNodes[2].InnerText = showScheduleItem.StartTime + "-" + showScheduleItem.EndTime;
wideTextNodes[0].InnerText = "科目:" + showScheduleItem.LessonName;
wideTextNodes[1].InnerText = "教室:" + showScheduleItem.ClassRoom;
wideTextNodes[2].InnerText = "時間:" + showScheduleItem.StartTime + "-" + showScheduleItem.EndTime;
var wideBingElement = wideTileXml.GetElementsByTagName("binding")[0];
var importedNode = narrowTileXml.ImportNode(wideBingElement, true);
narrowTileXml.GetElementsByTagName("visual")[0].AppendChild(importedNode);
for (int i = 0; i < 5; i++)
{
TileUpdateManager.CreateTileUpdaterForApplication().Update(new TileNotification(narrowTileXml));
}
}
ImportNode的方法創建一個我的寬綁定元素的一個新的拷貝在我的方的文檔的環境中。ImportNode方法的參數是我想要導入的元素和一個bool值,代表是否我想要導入子節點。然後使用AppendChild元素將它插入到narrowTileXml裏面,從而能構成和上面Xml模板一樣的數據類型。只要小心組合,什麼樣的模板都能巧妙組合到一塊。
最後,我們同樣的5次通知更新。現在,寬磁貼也能獲取到更新了。
關於磁貼動態更新就到這裏了。
推薦兩篇關於磁貼好博文:http://blogs.msdn.com/b/windowsappdev_cn/archive/2012/04/20/10295998.aspx
http://blogs.msdn.com/b/windowsappdev_cn/archive/2012/04/24/10297319.aspx
更新徽章(Badge)
什麼是Badge呢。看下圖:
這裏紅色方塊處就是徽章。徽章可以是數字(1-99之間)或者是圖片(圖片好像是微軟定義好的)。圖片定義:http://msdn.microsoft.com/en-us/library/windows/apps/hh761458.aspx
下面我們就來創建這麼一個方法添加到MainPage。
private void UpdateBadge()
{
BadgeTemplateType templateType = BadgeTemplateType.BadgeGlyph;
XmlDocument badgeXml = BadgeUpdateManager.GetTemplateContent(templateType);
((XmlElement)badgeXml.GetElementsByTagName("badge")[0]).SetAttribute("value", "attention");
for (int i = 0; i < 5; i++)
{
BadgeUpdateManager.CreateBadgeUpdaterForApplication().Update(new BadgeNotification(badgeXml));
}
}
更新徽章也是需要模版的,微軟就提供了兩個模版,一個是BadgeGlyph,一個是BadgeNumber,和更新Tile一樣,獲取模版的內容,然後設置value這個屬性,值爲attention時是顯示一個歎號,其他圖片值請看:http://msdn.microsoft.com/en-us/library/windows/apps/hh761458.aspx。如果是BadgeNumber模板,那麼”attention“就換爲"3",就顯示3這個數字了。同樣的,我們也重複5次通知更新。
現在,在MainPage的構造函數的最後添加:
UpdateBadge();
編譯運行就能看到歎號了。
本節就到這裏了,繼續學習:<win8>(五)實例講解win8(XAML+C#)開發--------課程表:Appbar,FilePicker,啓動頁面(動畫)
微軟官方示例:App tiles and badges sample
本次工程下載:http://dl.dbank.com/c0pnham1f1