XAML in Xamarin.Forms 基礎篇 電子書

XAML in Xamarin.Forms 基礎篇 電子書
XAML in Xamarin.Forms 基礎篇 電子書

Xamarin.Forms 快速入門 電子書

Xamarin.Forms 快速入門 電子書
Xamarin.Forms 快速入門 電子書

2014/07/13

如何產生 Windows Store App 的側載 Sideloading 的套件 Package

首先,使用 Visual Studio 2013 打開您的Windows Store App專案,從功能表選擇 [專案] > [市集] > 建立應用程式套件,如下圖所示:


請在 [建立應用程式套件] 對話窗中的 您要建置套件以上傳到 Windows 市集嗎?
請選擇 [否] 按鈕,接著點選右下角的 [下一步] 按鈕。

接下來您會看如下圖的對話窗,在 選取要建立的套件和方案組態對應 (左下角),您可以選擇 Neutral,表示該套件可以安裝在任何作業系統下 x86, x64, ARM,接著按下 [建立] 按鈕,則 Visual Studio 會開始幫忙建立這個App 可以用於側載的套件。


當 App 側載套件已經產生完成後,他會告訴您這些套件產生在哪個目錄下,您可以點選這個目錄連結,檔案總管會自動切換到這個目錄下。


當我們用檔案總管打開上圖的路徑後,您會看到如下圖的內容:
其中,下圖紅線框住的目錄,您可以使用任何壓縮工具將其壓縮起來,並且將這個壓縮檔案提供給需要側載的測試人員,他們就可以進行側載了。








如何得知您的電腦上安裝了那些 .Net Framework 版本 CLR

想要知道您的電腦上安裝了那些 .Net Framework CLR 版本,您可以執行 Clrver.exe 這個工具。

想要找到與啟動這個工具,有底下幾種方法:


  • 若您安裝的Visual Studio 2013,請使用命令提示字元或者檔案總管,切換到這個目錄下

    C:\Program Files (x86)\Microsoft Visual Studio 12.0\Common7\Tools
接著在命令提示字元中輸入指令 ClrVer ,就會看到底下結果了

C:\Program Files (x86)\Microsoft Visual Studio 12.0\Common7\Tools>Clrver

Microsoft (R) .NET CLR Version Tool  Version 4.0.30319.33440
Copyright (c) Microsoft Corporation.  All rights reserved.

Versions installed on the machine:
v2.0.50727
v4.0.30319

C:\Program Files (x86)\Microsoft Visual Studio 12.0\Common7\Tools>



2014/07/09

在 Windows 8.1 中,如何將 BitmapImage 的圖片內容透過 WriteableBitmap 寫入到磁碟檔案上

WriteableBitmap 是個很好用的程式庫,因為我們可以透過 WriteableBitmap 任意繪製與產生您所想要的圖片與內容,不過,要如何將 WriteableBitmap 的圖片內容,轉換成為圖片檔案呢(jpg, jpeg, png)?

在底下的程式碼,我們從 App Package 套件中的 Assets 目錄下,讀入一個圖片檔案,並且將這個圖片檔案設定到 BitmapImage 物件中,這是為了要知道這個圖片的長度與寬度。

接著,我們產生一個 WriteableBitmap 物件,在建構式中,我們傳入的 WriteableBitmap 所需要的寬度與高度,接著,將剛剛讀入的圖片檔案,使用 SetSourceAsync 設定到 WriteableBitmap 物件上,接著,我們就可以透過 SaveToFile 這個方法,把這個 WriteableBitmap 寫入到圖片檔案內。

            StorageFile storageFile = await StorageFile.GetFileFromApplicationUriAsync(new Uri("ms-appx:///Assets/Images/Pages/PageBackground.jpg"));
            IRandomAccessStream stream = await storageFile.OpenAsync(FileAccessMode.Read);
            BitmapImage bitmapImage = new BitmapImage();
            await bitmapImage.SetSourceAsync(stream);
            stream.Seek(0);

            var wb1 = new WriteableBitmap(bitmapImage.PixelWidth, bitmapImage.PixelHeight);
            await wb1.SetSourceAsync(stream);
            StorageFile sf1 = await ApplicationData.Current.LocalFolder.CreateFileAsync("your.png");
            await SaveToFile(wb1, sf1, BitmapEncoder.PngEncoderId);



        public async Task SaveToFile(WriteableBitmap writeableBitmap, IStorageFile outputFile, Guid encoderId)
        {
            try
            {
                Stream stream = writeableBitmap.PixelBuffer.AsStream();
                byte[] pixels = new byte[(uint)stream.Length];
                await stream.ReadAsync(pixels, 0, pixels.Length);

                using (var writeStream = await outputFile.OpenAsync(FileAccessMode.ReadWrite))
                {
                    var encoder = await BitmapEncoder.CreateAsync(encoderId, writeStream);
                    encoder.SetPixelData(
                        BitmapPixelFormat.Bgra8,
                        BitmapAlphaMode.Premultiplied,
                        (uint)writeableBitmap.PixelWidth,
                        (uint)writeableBitmap.PixelHeight,
                        96,
                        96,
                        pixels);
                    await encoder.FlushAsync();

                    using (var outputStream = writeStream.GetOutputStreamAt(0))
                    {
                        await outputStream.FlushAsync();
                    }
                }
            }
            catch (Exception ex)
            {
                string s = ex.ToString();
            }
        }




2014/07/02

安裝 WinRT App 發生問題之除錯方法

經常有些時候,我們在安裝(不論透過市集或者使用 Sideloading 側載方式)App,有些時候會發生錯誤或者異常,我們可以透過 [事件檢視器] 來查看這些Windows Store App 再進行佈署、安裝、註冊的時候,發生了甚麼問題。

請使用滑鼠右擊螢幕左下方的視窗圖示,此時會彈出下圖對話窗,請選擇 [事件檢視器]


 我們需要觀察 事件檢視器 中的這三個節點上的資料
Application And Services Logs > Microsoft > Windows > AppXDeployment
Application And Services Logs > Microsoft > Windows > AppXDeployment-Server
Application And Services Logs > Microsoft > Windows > AppXPackagingOM


 在下圖中,我們展示了查看某個錯誤訊息,這是屬於 AppXDeployment-Server
我們看到這個訊息顯示了:
錯誤 0x80073CF9: AppX 部署操作失敗。此失敗的特定錯誤文字是: 另一個使用者已安裝此應用程式的未封裝版本。目前的使用者無法使用已封裝的版本來取代此版本。衝突的套件是 CLACOMUSICCORPORATION.MusicPlayAlong,它是由 CN=327F2EE7-B787-4EC2-8B56-6B65F0CBB4FB 發行。

記錄檔名稱:         Microsoft-Windows-AppXDeploymentServer/Operational
來源:            Microsoft-Windows-AppXDeployment-Server
日期:            2014/6/21 下午 08:19:46
事件識別碼:         404
工作類別:          (3)
層級:            錯誤
關鍵字:           AppXDeploymentServer 關鍵字
使用者:           SYSTEM
電腦:            VulcanHome81
描述:
錯誤 0x80073CF9: AppX 部署操作失敗。此失敗的特定錯誤文字是: 另一個使用者已安裝此應用程式的未封裝版本。目前的使用者無法使用已封裝的版本來取代此版本。衝突的套件是 CORPORATION.MPA,它是由 CN=32E7-B787-4EC2-8B56-6B65F4FB 發行。


事件 Xml:
<Event xmlns="http://schemas.microsoft.com/win/2004/08/events/event">
  <System>
    <Provider Name="Microsoft-Windows-AppXDeployment-Server" Guid="{3F471139-ACB7-4A01-B7A7-FF5DA4BA2D43}" />
    <EventID>404</EventID>
    <Version>0</Version>
    <Level>2</Level>
    <Task>3</Task>
    <Opcode>0</Opcode>
    <Keywords>0x4000000000000001</Keywords>
    <TimeCreated SystemTime="2014-06-21T12:19:46.781919400Z" />
    <EventRecordID>63324</EventRecordID>
    <Correlation ActivityID="{2363FD72-8D4A-0001-02FE-63234A8DCF01}" />
    <Execution ProcessID="4572" ThreadID="4944" />
    <Channel>Microsoft-Windows-AppXDeploymentServer/Operational</Channel>
    <Computer>VulcanHome81</Computer>
    <Security UserID="S-1-5-18" />
  </System>
  <EventData>
    <Data Name="SummaryError">另一個使用者已安裝此應用程式的未封裝版本。目前的使用者無法使用已封裝的版本來取代此版本。衝突的套件是 CORPORATION.MPA,它是由 CN=32E7-B787-4EC2-8B56-6B65F4FB 發行。</Data>
    <Data Name="ErrorCode">0x80073cf9</Data>
  </EventData>
</Event>











SuspensionManager & NavigationHelper 之 App Lifecycle生命週期會使用到的相關事件與呼叫順序

想要充分發揮 WinRT & Windows Phone Universal App 效能,您一定要知道應用程式生命週期的相關知識,這裡,做個總結。當從App開始啟動後、到切換到不同的頁面、進入到 Suspend 模式下、重新回到App執行模式下等相關事件的執行順序。

當App在不同執行模式下運作,或者切換頁面的時候,您需要明確的掌握到那些事件會被執行,而且這些事件被呼叫的順序,如此,您方能夠有效的控制App的整體狀態與運作行為。

當App第一次啟動的時候,相關的事件呼叫順序
  • App.OnLaunched 事件(也就是 PreviousExecutionState 為 Nothing)
  • 第一個頁面.OnNavigatedTo 事件
  • 第一個頁面.LoadState 事件

當App進入到 Suspended 模式下,相關事件的呼叫順序
  • App.OnSuspending 事件
  • 第一個頁面.OnNavigatedFrom 事件
  • 第一個頁面.SaveState 事件

使用者把App從 Suspended 模式下,切換為正在顯示的相關事件呼叫順序
  • App.OnResuming 事件

使用者或者作業系統把 App 終止(例如使用者使用工作管理員強制關閉該App),相關事件呼叫順序
  • App.OnSuspending 事件
  • 第一個頁面.OnNavigatedFrom 事件
  • 第一個頁面.SaveState 事件


使用者從第一個頁面切換到第二個頁面的相關事件呼叫順序
  • 第一個頁面.OnNavigatingFrom事件
  • 第一個頁面.SaveState 事件
  • 第一個頁面.OnNavigatedFrom 事件
  • 第二個頁面.LoadState 事件
  • 第二個頁面.OnNavigatedTo 事件

使用者從第二個頁面回到第一個頁面的相關事件呼叫
  • 第二個頁面.OnNavigatingFrom事件
  • 第二個頁面.SaveState 事件
  • 第二個頁面.OnNavigatedFrom 事件
  • 第一個頁面.LoadState 事件
  • 第一個頁面.OnNavigatedTo 事件

使用者再次切換到第二個頁面的相關事件呼叫
  • 第一個頁面.OnNavigatedFrom 事件
  • 第一個頁面.OnNavigatingFrom事件
  • 第一個頁面.SaveState 事件
  • 第一個頁面.OnNavigatedFrom事件
  • 第二個頁面.LoadState 事件
  • 第二個頁面.OnNavigatedTo 事件

App進入到 Suspended 模式下的相關事件呼叫(例如:切換到桌面環境中,或者其他App)
  • App.OnSuspending 事件
  • 第二個頁面.SaveState 事件
  • 第二個頁面.OnNavigatedFrom 事件

App從 Suspended模式下,回到正常運作模式下的相關事件呼叫
  • App.OnResuming


App進入到 Suspended 模式下並且被作業系統強制終止
  • App.OnSuspending 事件
  • 第二個頁面.SaveState 事件
  • 第二個頁面.OnNavigatedFrom 事件

Microsoft DirectX Graphics Infrastructure (DXGI) 角色

DXGI 是一組用來設定和管理低階圖形與圖形卡資源的 API。如果沒有它,您就無法將遊戲的圖形繪製到視窗中!

您可以用這種方式思考 DXGI:為了直接存取 GPU 並管理其資源,必須有一個對應用程式描述它的方式。您所需最重要的 GPU 資訊就是繪製像素的位置,這樣它才能夠將這些像素傳送到螢幕上。這通常稱為「背景緩衝區」—GPU 記憶體中的一個位置,您可以在該處繪製像素,然後「翻轉」或「交換」,並在收到重新整理訊號時傳送到螢幕上。DXGI 可讓您取得該位置以及使用該緩衝區 (稱為「交換鏈結」,因為這是可交換的緩衝區鏈結,允許多個緩衝處理策略) 的方法。

若要這麼做,您需要有可寫入交換鏈結的存取權,以及將顯示交換鏈結之目前背景緩衝區的視窗控制代碼。您還需要將兩者連接,以確保作業系統會在您要求以背景緩衝區的內容重新整理視窗時,執行該動作。

開發 universal app ,如何在程式碼中,標示與切換 Windows store 或者 Windows phone 專用的程式碼

當我們在開發 universal app,讓 App 可以同時在兩個平台上執行,但是,某些情況,我們需要在特定平台上寫入只有該平台才擁有的功能,這個時候,您可以使用 [條件式編譯的符號] 來區隔,Windows Phone 使用 WINDOWS_PHONE_APP,而Windows Store 則使用 WINDOWS_APP。

那麼,我們要如何在 Visual Studio 上換不同平台,看到這些程式碼是否有效呢?
我們使用下圖做說明, NavigationHelper.cs 是共用程式碼區域的C#,在下圖內,我們看到了這行程式碼,只有 Windows Phone 才會使用的,如底下這行程式碼:

Windows.Phone.UI.Input.HardwareButtons.BackPressed += HardwareButtons_BackPressed;

而底下的程式碼,是在 Windows Store App 環境下才會執行的。

                // 只有佔用整個視窗時才適用鍵盤和滑鼠巡覽
                if (this.Page.ActualHeight == Window.Current.Bounds.Height &&
                    this.Page.ActualWidth == Window.Current.Bounds.Width)
                {
                    // 直接接聽視窗,所以不需要焦點
                    Window.Current.CoreWindow.Dispatcher.AcceleratorKeyActivated +=
                        CoreDispatcher_AcceleratorKeyActivated;
                    Window.Current.CoreWindow.PointerPressed +=
                        this.CoreWindow_PointerPressed;
                }

我們可以使用下圖編號1標示的地方,切換使用不同平台的 [條件式編譯的符號] ,如此,我們就可以看到不同平台的程式碼,是否有問題發生。

在下圖中,我們使用的是 Windows Store App平台的程式碼,您會看到了 Windows Phone 專屬的程式碼變成不可用的灰色了。


在下圖中,我們使用的是 Windows Phone App平台的程式碼,您會看到 Windows Phone 會用到的程式碼變成可用的黑色了。



2014/07/01

在WinRT Windows Phone App 中,想要下載較大的圖片、音樂、二進位檔案的方法

平常我們在 WinRT 或者 Windows Phone App中,想要取得網路上的檔案,可以透過 HttpClient 物件來進行取得這些檔案,不過,當這些網路上的檔案過大的時候,HttpClient 可能無法處理,這個時候我們就可以透過 BackgroundDownloader 物件來幫助我們做到背景下載這些檔案,卻又不會影響到 UI thread 執行緒,也就是不會造成您的 UI 凍結的問題。


            BackgroundDownloader downloader = new BackgroundDownloader();
             StorageFile destinationFile = await ApplicationData.Current.LocalFolder.CreateFileAsync("vulcan.mp3");
            DownloadOperation download = downloader.CreateDownload(new Uri("http://host/path/vulcan.mp3), destinationFile);
            await download.StartAsync();
            ResponseInformation response = download.GetResponseInformation();

在 WinRT & Windows Phone 中,如何將顏色代碼文字,轉換成為 Windows.UI.Color 物件

底下的範例程式碼,提供了如何將顏色的代碼, #FF012345 或者 #012345 這樣的代碼,轉換成為 Windows.UI.Color 的物件。

        public static Color Parse(string color)
        {
            var offset = color.StartsWith("#") ? 1 : 0;

            string tt = color.Substring(offset);

            if (tt.Length > 6)
            {
                var a = Byte.Parse(color.Substring(0 + offset, 2), NumberStyles.HexNumber);
                var r = Byte.Parse(color.Substring(2 + offset, 2), NumberStyles.HexNumber);
                var g = Byte.Parse(color.Substring(4 + offset, 2), NumberStyles.HexNumber);
                var b = Byte.Parse(color.Substring(6 + offset, 2), NumberStyles.HexNumber);

                return Color.FromArgb(a, r, g, b);
            }
            else
            {
                var a = Byte.Parse("FF", NumberStyles.HexNumber);
                var r = Byte.Parse(color.Substring(0 + offset, 2), NumberStyles.HexNumber);
                var g = Byte.Parse(color.Substring(2 + offset, 2), NumberStyles.HexNumber);
                var b = Byte.Parse(color.Substring(4 + offset, 2), NumberStyles.HexNumber);

                return Color.FromArgb(a, r, g, b);
            }
        }



在 WinRT & Windows Phone 中,將非同步呼叫,轉換成為同步呼叫

有些時候,也許您不想要採用非同步方式的呼叫,不過,您所擁有的程式庫 Library ,卻都只有提供非同步方式呼叫的方法,這個時候,您可以採用底下的方式來將非同步的呼叫,轉換成為同步方式的呼叫。

                Task.Factory.StartNew(async () =>
                {
                    await IsolatedStorageJSON< List < AbnormalException > >.SaveToFileAsync("", "AbnormalException", listAbnormalException);
                });


另外,可以採用底下的方式(底下的範例是因為呼叫了 GetFileAsync 會傳回 IAsyncOperation<StorageFile> ,因此,我們可以透過這樣的方式,綁定了 Completed 事件,來判斷或者取回此次非同步呼叫的結果):

        public static void WinRTAsyncIntro()
        {
            IAsyncOperation< StorageFile > asyncOp = KnownFolders.PicturesLibrary.GetFileAsync("vulcan.png");
            asyncOp.Completed = OpCompleted;
        }
        private static void OpCompleted(IAsyncOperation< StorageFile > asyncOp, AsyncStatus status)
        {
                try
                {
                    StorageFile file = asyncOp.GetResults(); 
                }
                catch (Exception ex)
                {
                }

            asyncOp.Close();
        }

這是 GetFileAsync 的語法
public IAsyncOperation<StorageFile> GetFileAsync(
  string name
)

這裡還有另外一個方法,是比較有效率的,尤其是當您在 WinRT 系統下,需要用到 deferral 情境下,可以使用底下的方法,不過,需要特別注意的,這個方法,會造成當時的執行緒被鎖定,若您是在 UI Thread 下呼叫底下方法,會造成您的UI被凍結。

StorageFile myFile = KnownFolders.PicturesLibrary.GetFileAsync("vulcan.png").AsTask().GetAwaiter().GetResult();