WP - 增加在WP8下的WP7.1 App也有Flip Tile

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:執行結果與畫面

P02P03P04

注意上述的紫色圖示為執行結果。

 

======

以上是簡單根據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

 

Dotblogs Tags: