Windows Phone - 增加在WP8下的WP7.1 App也有Flip Tile
在<Windows Phone 8 – Tiles大進化>提到了WP 8新的三種Tile Templates,那舊有WP 7.1的APP
想要這樣的Tile怎麼辦呢?我只能說有點冏的抱歉了,WP 7.1的App想要有WP 8的Tile,根據
官方的<Adding Windows Phone 8 Tile functionality to Windows Phone OS 7.1 apps>說明,只具有
「Flip Template」的效果,所以往下來就來看看怎麼做吧。
步驟1:在WMAppManifest.xml中增加新的標籤<AppExtra />;
在<App />標籤上方加上<AppExtra />的內容,並且宣告以支援WP8的效果,如下:
1: <AppExtra xmlns="" AppPlatformVersion="8.0">
2: <Extra Name="Tiles" />
3: </AppExtra>
4: <App />
步驟2:建立一個類別,包裝要建立WP 7.8 Tile的邏輯;
以下細部說明每個步驟:
(2-1). 準備三個Size的Tile,以支援Flip Tile template;
參考<Tiles and notifications for Windows Phone>中定義的三種Tile的Size,如下:
Flip and Cycle | Iconic | |
Small | 159 x 159 pixels | 110 x 110 pixels |
Medium | 336 x 336 pixels | 202 x 202 pixels |
Large | 691 x 336 pixels | N/A |
(2-2). 增加檢查目前WP OS版本的功能;
1: //指定預設最小的版本號:8.0
2: private static Version TargetedVersion = new Version(8, 0);
3:
4: /// <summary>
5: /// 目前WP版本是否為目標版本。
6: /// </summary>
7: public static bool IsTargetedVersion
8: {
9: get
10: {
11: //取得版本為8.0.9903.0 > 8.0
12: return Environment.OSVersion.Version >= TargetedVersion;
13: }
14: }
(2-3). 建立更新WP7.8 Flip Tile Template的邏輯;
1: /// <summary>
2: /// 建立更新Flip Tile Template的邏輯。
3: /// </summary>
4: /// <param name="title">正面標題</param>
5: /// <param name="backTitle">背面標題</param>
6: /// <param name="backContent">背面內容</param>
7: /// <param name="wideBackContent">寬背面內容</param>
8: /// <param name="count">Count</param>
9: /// <param name="tileId">Tile ID</param>
10: /// <param name="smallBackgroundImage">小背圖</param>
11: /// <param name="backgroundImage">中背圖</param>
12: /// <param name="backBackgroundImage">背中背圖</param>
13: /// <param name="wideBackgroundImage">寬背圖</param>
14: /// <param name="wideBackBackgroundImage">背寬背圖</param>
15: public static void UpdateFlipTile(
16: string title,
17: string backTitle,
18: string backContent,
19: string wideBackContent,
20: int count,
21: Uri tileId,
22: Uri smallBackgroundImage,
23: Uri backgroundImage,
24: Uri backBackgroundImage,
25: Uri wideBackgroundImage,
26: Uri wideBackBackgroundImage)
27: {
28: if (IsTargetedVersion)
29: {
30: // Get the new FlipTileData type.
31: Type flipTileDataType = Type.GetType("Microsoft.Phone.Shell.FlipTileData, Microsoft.Phone");
32:
33: // Get the ShellTile type so we can call the new version of "Update" that takes the new Tile templates.
34: Type shellTileType = Type.GetType("Microsoft.Phone.Shell.ShellTile, Microsoft.Phone");
35:
36: // Loop through any existing Tiles that are pinned to Start.
37: foreach (var tileToUpdate in ShellTile.ActiveTiles)
38: {
39: // Look for a match based on the Tile's NavigationUri (tileId).
40: if (tileToUpdate.NavigationUri.ToString() == tileId.ToString())
41: {
42: // Get the constructor for the new FlipTileData class and assign it to our variable to hold the Tile properties.
43: var UpdateTileData = flipTileDataType.GetConstructor(new Type[] { }).Invoke(null);
44:
45: // Set the properties.
46: SetProperty(UpdateTileData, "Title", title);
47: SetProperty(UpdateTileData, "Count", count);
48: SetProperty(UpdateTileData, "BackTitle", backTitle);
49: SetProperty(UpdateTileData, "BackContent", backContent);
50: SetProperty(UpdateTileData, "SmallBackgroundImage", smallBackgroundImage);
51: SetProperty(UpdateTileData, "BackgroundImage", backgroundImage);
52: SetProperty(UpdateTileData, "BackBackgroundImage", backBackgroundImage);
53: SetProperty(UpdateTileData, "WideBackgroundImage", wideBackgroundImage);
54: SetProperty(UpdateTileData, "WideBackBackgroundImage", wideBackBackgroundImage);
55: SetProperty(UpdateTileData, "WideBackContent", wideBackContent);
56:
57: // Invoke the new version of ShellTile.Update.
58: shellTileType.GetMethod("Update").Invoke(tileToUpdate, new Object[] { UpdateTileData });
59: break;
60: }
61: }
62: }
63:
64: }
65:
66: /// <summary>
67: /// 更新物件指定的屬性與值。
68: /// </summary>
69: /// <param name="instance"></param>
70: /// <param name="name"></param>
71: /// <param name="value"></param>
72: private static void SetProperty(object instance, string name, object value)
73: {
74: var setMethod = instance.GetType().GetProperty(name).GetSetMethod();
75: setMethod.Invoke(instance, new object[] { value });
76: }
該程式透過指定Assembler的方式載入WP 8中的新Dll,包括:FlipTileData與ShellTile類別,進一步進行更新,其道理非常容易懂。
要特別注意的是:tileId屬性。如果是手動釘選的Tile (Application Tile),它的tildId是"/",如果是程式產生的,則是自訂的值,
例如:
1: //指定了TileId為 /MainPage.xaml
2: ShellTile.Create(new Uri("/MainPage.xaml", UriKind.Relative),
3: new StandardTileData
4: {
5: Title="AppTile"
6: });
這將會影響,所以建議,可以在程式一開始的時候就透過程式更新ShellTile.ActiveTiles.First()為Flip Tile,這樣用戶釘上Tile時,
預設就是Flip Tile。
[備註]
我有試過改寫支援CycleTileData,但沒有辦法正常執行,但我會再試看看的。
(2-4). 整理一下Code,加上二個按鈕,分別為建立Tile與更新Tile;
1: <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
2: <StackPanel>
3: <Button x:Name="btnCreateSTile" Content="Create Tile" Click="btnCreateSTile_Click" />
4: <Button x:Name="btnUpdateTile78" Content="Update WP 7.8 Tile" Click="btnUpdateTile78_Click" />
5: </StackPanel>
6: </Grid>
加上事件的Code;
1: private void btnCreateSTile_Click(object sender, RoutedEventArgs e)
2: {
3: ShellTile tTile = ShellTile.ActiveTiles.First();
4: if (tTile == null)
5: MessageBox.Show("no tile!!");
6: ShellTile.Create(new Uri("/MainPage.xaml", UriKind.Relative),
7: new StandardTileData
8: {
9: Title="AppTile"
10: });
11: }
12:
13: private void btnUpdateTile78_Click(object sender, RoutedEventArgs e)
14: {
15: ShellTile tTile = ShellTile.ActiveTiles.First();
16: if (Tile2New.IsTargetedVersion)
17: {
18: #region FlipTileData
19: Tile2New.UpdateFlipTile("WP7.8 Tile", "WP7.8 Tile_Back", "挑戰看看, 'WP7.8 Tile'!", "來挑戰看看 'WP7.8 Tile'!!", 0,
20: new Uri("/MainPage.xaml", UriKind.Relative),
21: new Uri("/Images/phone_tile159.png", UriKind.Relative),
22: new Uri("/Images/phone_tile336.png", UriKind.Relative),
23: null,
24: new Uri("/Images/phone_tile691.png", UriKind.Relative),
25: null);
26: #endregion
27: }
28: }
整理上述完整的Code;
1: public class Tile2New
2: {
3: //指定預設最小的版本號:8.0
4: private static Version TargetedVersion = new Version(8, 0);
5:
6: /// <summary>
7: /// 目前WP版本是否為目標版本。
8: /// </summary>
9: public static bool IsTargetedVersion
10: {
11: get
12: {
13: //取得版本為8.0.9903.0 > 8.0
14: return Environment.OSVersion.Version >= TargetedVersion;
15: }
16: }
17:
18: /// <summary>
19: /// 建立更新Flip Tile Template的邏輯。
20: /// </summary>
21: /// <param name="title">正面標題</param>
22: /// <param name="backTitle">背面標題</param>
23: /// <param name="backContent">背面內容</param>
24: /// <param name="wideBackContent">寬背面內容</param>
25: /// <param name="count">Count</param>
26: /// <param name="tileId">Tile ID</param>
27: /// <param name="smallBackgroundImage">小背圖</param>
28: /// <param name="backgroundImage">中背圖</param>
29: /// <param name="backBackgroundImage">背中背圖</param>
30: /// <param name="wideBackgroundImage">寬背圖</param>
31: /// <param name="wideBackBackgroundImage">背寬背圖</param>
32: public static void UpdateFlipTile(
33: string title,
34: string backTitle,
35: string backContent,
36: string wideBackContent,
37: int count,
38: Uri tileId,
39: Uri smallBackgroundImage,
40: Uri backgroundImage,
41: Uri backBackgroundImage,
42: Uri wideBackgroundImage,
43: Uri wideBackBackgroundImage)
44: {
45: if (IsTargetedVersion)
46: {
47: // Get the new FlipTileData type.
48: Type flipTileDataType = Type.GetType("Microsoft.Phone.Shell.FlipTileData, Microsoft.Phone");
49:
50: // Get the ShellTile type so we can call the new version of "Update" that takes the new Tile templates.
51: Type shellTileType = Type.GetType("Microsoft.Phone.Shell.ShellTile, Microsoft.Phone");
52:
53: // Loop through any existing Tiles that are pinned to Start.
54: foreach (var tileToUpdate in ShellTile.ActiveTiles)
55: {
56: // Look for a match based on the Tile's NavigationUri (tileId).
57: if (tileToUpdate.NavigationUri.ToString() == tileId.ToString())
58: {
59: // Get the constructor for the new FlipTileData class and assign it to our variable to hold the Tile properties.
60: var UpdateTileData = flipTileDataType.GetConstructor(new Type[] { }).Invoke(null);
61:
62: // Set the properties.
63: SetProperty(UpdateTileData, "Title", title);
64: SetProperty(UpdateTileData, "Count", count);
65: SetProperty(UpdateTileData, "BackTitle", backTitle);
66: SetProperty(UpdateTileData, "BackContent", backContent);
67: SetProperty(UpdateTileData, "SmallBackgroundImage", smallBackgroundImage);
68: SetProperty(UpdateTileData, "BackgroundImage", backgroundImage);
69: SetProperty(UpdateTileData, "BackBackgroundImage", backBackgroundImage);
70: SetProperty(UpdateTileData, "WideBackgroundImage", wideBackgroundImage);
71: SetProperty(UpdateTileData, "WideBackBackgroundImage", wideBackBackgroundImage);
72: SetProperty(UpdateTileData, "WideBackContent", wideBackContent);
73:
74: // Invoke the new version of ShellTile.Update.
75: shellTileType.GetMethod("Update").Invoke(tileToUpdate, new Object[] { UpdateTileData });
76: break;
77: }
78: }
79: }
80: }
81:
82: /// <summary>
83: /// 更新物件指定的屬性與值。
84: /// </summary>
85: /// <param name="instance"></param>
86: /// <param name="name"></param>
87: /// <param name="value"></param>
88: private static void SetProperty(object instance, string name, object value)
89: {
90: var setMethod = instance.GetType().GetProperty(name).GetSetMethod();
91: setMethod.Invoke(instance, new object[] { value });
92: }
93: }
步驟3:執行結果與畫面;
注意上述的紫色圖示為執行結果。
======
以上是簡單根據MSDN上的說明,加以實作後得到的心得,大家參考一下著用吧。
不過我從以前就一直覺得WMAppManifest.xml一定還內藏了很多特殊的標籤沒有被釋放出來,就看WP的演化吧。
References:
‧Adding Windows Phone 8 Tile functionality to Windows Phone OS 7.1 apps
‧Flip Tile template for Windows Phone 8
‧Flip Tile template for Windows Phone 8
‧Iconic Tile template for Windows Phone 8
‧Cycle Tile template for Windows Phone 8