XAML in Xamarin.Forms 基礎篇 電子書

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

Xamarin.Forms 快速入門 電子書

Xamarin.Forms 快速入門 電子書
Xamarin.Forms 快速入門 電子書
顯示具有 Windows Phone 標籤的文章。 顯示所有文章
顯示具有 Windows Phone 標籤的文章。 顯示所有文章

2014/07/02

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 事件

開發 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();

2014/06/30

將圖片檔案直接設定到 BitmapImage

若想再增加 XAML 對於圖片檔案顯示的速度,您可以使用 BitmapImage 物件,將圖片檔案讀入到 BitmapImage 物件內,接著,您就可以將這個 BitmapImage 物件 設定到 XAML Image Element的 Source 屬性上,如此,就可以直接顯示出該圖片。

                StorageFile storageFile = await ApplicationData.Current.LocalFolder.GetFolderAsync(filename);
                IRandomAccessStream stream = await storageFile.OpenAsync(FileAccessMode.Read);
                BitmapImage bitmapImage = new BitmapImage();
                await bitmapImage.SetSourceAsync(stream);

                 this.XAMLImageElement.Source = bitmapImage ;



使用 HttpClient 下載圖片檔案到本機的 Isolated Storage

若您在 WinRT 系統下,有些時候您會想要自己將網路上的圖片檔案,下載到本機  Isolated Storage 檔案系統內,這個圖片檔案可以做為快取之用,下次當要顯示該圖片的時候,就可以直接從本機  Isolated Storage 目錄下,直接讀取這個圖片檔案出來顯示。

            var httpClient = new HttpClient();

            var randomAccessStream = new InMemoryRandomAccessStream();

            var contentUri = "http://host/path/path/name";
            var filename = "your file name";

            using (var responseStream = await httpClient.GetStreamAsync(new Uri(contentUri)))

                 StorageFolder folder = await ApplicationData.Current.LocalFolder;
 
                using (var fileStream = await folder.OpenStreamForWriteAsync(filename , CreationCollisionOption.ReplaceExisting))
                {
                    await responseStream.CopyToAsync(fileStream);
                    responseStream.Dispose();
                }



如何判斷 StorageFile 或者 StorageFolder 所指向的檔案是否存於 Isolated Storage 內

之前不論在寫 WinRT 或者 Windows Phone App的時候,一定會遇到這樣的需求,那就是想要檢查在 Isolated Storage 內的某個檔案是否存在,並且根據此一結果,決定接下來要怎麼繼續處理。


        public async Task 該圖片檔案是否已經存在於本機(string filename)
        {
            bool Exist = false;

            var md5String = MD5Core.GetHashString(圖片路徑);

            StorageFolder folder = await ApplicationData.Current.LocalFolder;
            var files = await folder.GetItemsAsync();
            Exist = files.FirstOrDefault(p => p.Name == filename) == null ? false : true;
            return Exist;
        }


在 Windows 8.1 底下使用 RenderTargetBitmap 來儲存 XAML Element 的圖片

有些時候,我們希望能夠儲存某個頁面或者某個XMAL控制項當時畫面結果,到本機上的圖片檔案中,我們就可以使用底下的程式碼來做到這樣的需求。

首先,我們使用建立個RenderTargetBitmap物件,並且使用了 RenderAsync 方法,產生該 XAML 控制項 gd測試圖片 的影像來源輸入的緩衝區資料流。

接著我們使用了 FileSavePicker 讓使用者選擇要將該圖片檔案儲存到本機的哪個目錄下。

最後,我們就可以透過 BitmapEncoder 物件,SetPixelData 與 FlushAsync 方法,將該影像來源的緩衝區資料流,寫入到檔案內。


            RenderTargetBitmap renderTargetBitmap = new RenderTargetBitmap();
            await renderTargetBitmap.RenderAsync(gd測試圖片);
            // 1. Get the pixels
            IBuffer pixelBuffer = await renderTargetBitmap.GetPixelsAsync();
            var pixels = await renderTargetBitmap.GetPixelsAsync();

            var filePicker = new FileSavePicker();

            filePicker.SuggestedStartLocation = PickerLocationId.DocumentsLibrary;

            var textFileExtension = new[] { ".jpg" };
            var dataFileExtension = new[] { ".png" };

            filePicker.FileTypeChoices.Add("JPG", textFileExtension);
            filePicker.FileTypeChoices.Add("PNG", dataFileExtension);

            IAsyncOperation< storagefile > asyncOp = filePicker.PickSaveFileAsync();
            StorageFile file = await asyncOp;

            if (file == null)
            {
                return;
            }

            
            using (IRandomAccessStream stream = await file.OpenAsync(FileAccessMode.ReadWrite))
            {
                var encoder = await
                    BitmapEncoder.CreateAsync(BitmapEncoder.JpegEncoderId, stream);
                byte[] bytes = pixels.ToArray();
                encoder.SetPixelData(BitmapPixelFormat.Bgra8,
                                     BitmapAlphaMode.Ignore,
                                     (uint)gd測試圖片.Width, (uint)gd測試圖片.Height,
                                     96, 96, bytes);

                await encoder.FlushAsync();
            }

2014/06/28

如何在 Windows 8 App 中,使用 XAML 做到 Responsive 響應式 設計

現在一般網頁開發,大多需要具備Responsive Web Design (RWD) 響應式網頁設計,也就是,能自動針對不同 size 的裝置調整網頁最佳的呈現方式,讓使用者操作經驗更好。

若我們在進行 C# / XAML 的 Windows Phone App 開發的時候,也希望我們的頁面能夠根據手機的轉向,自動進行調整,不需要任何的 [後置程式碼] (Code Behind) C# 程式碼來支援,也就是不需要透過任何的事件來呼叫與執行任何 C# 程式碼,這樣的需求,我們應該要如何做到呢?

這樣的問題是許多第一次接觸 Windows Phone App 的開發者所必定會遇到的問題,讓我們來看看底下的範例說明,在這個範例中,我們有兩個按鈕與一個文字要顯示在同一行中,當手機的轉向是直式的時候,會呈現如下圖的樣貌;這兩個按鈕分別要存在於左右兩邊,文字則需要顯示在兩個按鈕之間,而且中間的文字需要依據當時手機解析度,自動調整最大寬度與高度之可以最多顯示文字。


若手機轉個90度,上述需求需要同時存在,不過,在橫式頁面上,文字可以顯示的寬度會變得更大,而且可以看到的文字字數應該要更多,如同下圖所顯示。


這樣的需求真的可以做到嗎? 我們來看看這個頁面的 XAML 定義。

<!--LayoutRoot 是放置所有頁面的根資料格-->
    <Grid x:Name="LayoutRoot" Background="Transparent">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>
 
        <!--TitlePanel 包含應用程式的名稱和頁面標題-->
        <StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,17,0,28">
            <TextBlock Text="我的應用程式" Style="{StaticResource PhoneTextNormalStyle}" Margin="12,0"/>
            <TextBlock Text="頁面名稱" Margin="9,-7,0,0" Style="{StaticResource PhoneTextTitle1Style}"/>
        </StackPanel>
 
        <!--ContentPanel - 其他內容置於此-->
        <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
            <!--在這使用 Grid 來將這三個控制項定義在-->
            <Grid Height="100" VerticalAlignment="Top" >
                <!--左邊的按鈕-->
                <Button HorizontalAlignment="Left">Add</Button>
 
                <!--中間的文字-->
                <TextBlock Text="這是要 顯示的 文字內容 這是要 顯示的 文字內容 這是要 顯示的 文字內容 這是要 顯示的 文字內容 這是要 顯示的 文字內容 這是要 顯示的 文字內容 " Margin="100,0,100,0" TextWrapping="Wrap"/>
 
                <!--右邊的按鈕-->
                <Button HorizontalAlignment="Right">Add</Button>
            </Grid>
        </Grid>
 
    </Grid>

我們將這三個控制項使用 Grid 面板(Panel)定義在其裡面,並且記得:
左邊的按鈕
需要使用 HorizontalAlignment="Left",設定該按鈕需要往左對其

右邊的按鈕
需要使用 HorizontalAlignment="Right" ,設定該按鈕需要往右對其

中間的文字
請使用 Margin="100,0,100,0" 設定左右的邊界各為100,目的是要保留文字的左右顯示邊界,不要蓋到按鈕;接著在 TextBlock 控制向上設定屬性 TextWrapping="Wrap" ,讓 TextBlock 根據當時可用的空間,顯示出最多的文字。

這樣就可以做到 [響應式] (Responsive) 的 Windows Phone App 頁面設計技巧了。

若每次要測試手機轉向 直式 / 橫式 的執行結果,都要透過執行程式才能夠看到最後結果,那麼,您對於 Windows Phone 開發工具必定不是十分孰悉,記得這句話,若是可以在設計模式下就可以看到的結果,就要讓您的設計內容可以於設計模式下看到每個頁面的最後執行結果,不需要等到執行時期才能夠看到。(也許您會問說,這樣會有問題,有些頁面上面有許多控制項,裡面的資料需要等到執行時期才能夠透過 C# 程式透過本地檔案或者從網路抓取才能夠讀取出來,並且顯示在頁面上,例如,圖片檔案,JSON內容;不用擔心,您只需要學會設計時期的範例資料的功能,就可以讓您的App的每個頁面,在設計時期的時候,模擬出需要再執行時期才能夠看到的資料,這樣不但可以加入您的程式開發時程,而且可以讓您在設計時期,就可以知道未來執行後的每個頁面真實的樣貌,我會另外寫篇文章告訴大家如何做到這樣的需求)

請在您的 Visual Studio (或者 Blend (這是個好東西,想要成為 Windows Phone 開發專家,一定要學會 Blend) ),使用 [裝置] 視窗來調整您設計時期的頁面螢幕轉向,如下圖所示的紅色方框,左邊的圖示就是讓您的設計時期的手機螢幕轉向成為橫式,而右邊的圖示,就是可以將您設計時期的頁面轉向成為直式。








2014/06/26

在WinRT下,如何取得圖片檔案的內容或者該圖片的縮圖

往往當把圖片檔案儲存到本機的獨立儲存空間 (Isolated Storage),之後想要顯示該圖片,不過,有些時候這些圖片檔案可能會很大,而我們這個時候只想要顯示這些圖片的縮圖大小,作為讓使用者可以快速大量瀏覽或者選取之用,而不想要取得全尺寸的圖片。

這個時候,就可以用到這兩個方法:

StorageFile.GetThumbnailAsync(ThumbnailMode, UInt32, ThumbnailOptions)
依據縮圖的用途、要求的大小以及指定的選項,擷取檔案經過調整的縮圖影像。

StorageFile.GetScaledImageAsThumbnailAsync(ThumbnailMode, UInt32, ThumbnailOptions)
依據縮圖的用途、要求的大小和指定選項,取得縮放影像做為縮圖。

經過這樣的處理,我們就不再需要取得全尺寸的圖片資源,並且透過 XAML 設定來幫我們做圖片的縮放顯示處理,這樣可以大幅提升整體App的運作速度,當您要處理顯示很多圖片的時候,這是個不錯的優化改善方法。

如何針對 StorageFile物件把它關閉起來

一般我們在處理檔案的時候,若不再需要使用該檔案,就需要將這個資源關閉起來,可是,為什麼 StorageFile物件裡面,卻沒有任何關於 Close 這樣的輔助方法呢?

理由很簡單,因為,StorageFile 只是個抽象的路徑名稱,用來代表檔案系統中的某個檔案,也就是說,當您取得了 StorageFile物件後,例如,使用 StorageFolder.GetFileAsync (使用指定的檔案名稱來取得目前資料夾中的單一檔案。)來取得一個 StorageFile 物件,並不代表了這個檔案已經被開啟並且被鎖住了,這個 StorageFile 物件僅僅只是提供了一個參考到這個檔案的資訊而已。

若您實際取得該StorageFile的資料流(Stream),則您才是開始針對該檔案進行存取動作的開始,不過,當對於該檔案的資料流處理動作完成後,記得要將該資料流做關閉(Close)和 Dispose的動作。

您可以依據您的需求,參考底下四種方法,取得您所需求的資料流
StorageFile.OpenAsync 透過檔案開啟隨機存取資料流。

StorageFile.OpenReadAsync 透過目前的檔案開啟隨機存取資料流來讀取檔案內容。

StorageFile.OpenSequentialReadAsync 透過目前的檔案開啟循序存取資料流來讀取檔案內容。

StorageFile.OpenTransactedWriteAsync 開啟可用於異動寫入作業之檔案的隨機存取資料流。

StorageFile storageFile =
      await Windows.Storage.StorageFile.GetFileFromApplicationUriAsync(uri);

    var randomAccessStream = await storageFile.OpenReadAsync();
    Stream stream = randomAccessStream.AsStreamForRead();

在WinRT中,有沒有比較輕鬆容易的處理檔案解決方案

當我們在WinRT系統中,想要處理檔案動作,需要透過 StorageFolder取得一個StorageFile,接著要使用相對應的資料流開啟StorageFile指向的檔案,處理完成後,還要關閉與釋放這個資料流,真的有點繁瑣。

我們可以透過 FileIO Class ( 提供協助程式方法用於讀取和寫入檔案,這些檔案是由IStorageFile型別的物件所表示 ) 類別 與 PathIO Class ( 提供 Helper 方法,以使用絕對檔案路徑或 URI 來讀取和寫入檔案 ),來簡化後半段的動作;例如,我們只想針對該檔案讀取所有的文字內容或者將字串寫入到檔案內。

try
{
    if (file != null)
    {
        string fileContent = await PathIO.ReadTextAsync(filePathOrURI);
    }
}
// Handle errors with catch blocks
catch (FileNotFoundException)
{
    // For example, handle file not found
}

在範例中,filePathOrURI 是區域變數,其包含要讀取之檔案的 URI (例如應用程式 URI "ms-appdata://sampleFile.dat") 或檔案系統路徑 (例如 C:\examplepath\sampleFile.dat)。
在 readTextAsync 完成之後,fileContent 變數會取得檔案的內容做為文字字串。接著您可以依適合的情況處理內容。

關於實際更多用法,您可以參考 檔案存取範例

2014/06/25

在WinRT下,如何使用 StorageFile物件,設定該檔案為唯讀

若您有這樣的需求,想要將某個在 Isolated Storage 內的檔案,設定成為唯讀的屬性,此時,您會需要用到:

StorageFile.Properties
取得物件,用以存取檔案的內容相關屬性。

當取得了 StorageFile.Properties屬性後,他是個屬於 StorageItemContentProperties 類型的物件,代表了 提供檔案之內容相關屬性存取權的物件。

參考下列程式碼,您可以設定檔案為唯讀屬性

String key = "System.FileAttributes";
UInt32 FILE_ATTRIBUTES_READONLY = 1;
var pix = Windows.Storage.KnownFolders.PicturesLibrary;

var file = await pix.GetFileAsync("test.jpg");
String[] retrieveList = new String[] { key };

var props = await file.Properties.RetrievePropertiesAsync(retrieveList);

if (props != null)
{
    var temp = (UInt32)props[key] | FILE_ATTRIBUTES_READONLY;
    props[key] = temp;
}
else
{
    props = new Windows.Foundation.Collections.PropertySet();
    props.Add(key, FILE_ATTRIBUTES_READONLY);
}

await file.Properties.SavePropertiesAsync(props);

不需要經由使用者同意,就可以 WinRT App 存取的檔案系統有哪些?

這是個相當不錯的問題,其實我自己也花了不少時間,才逐步清楚這樣的狀況,尤其是在我要取得 [MCSD: Windows Store Apps Using C# 認證] 的時候,必須要對這樣的情境十分孰悉。

原則上,不需要經過使用者同意,而App可以存取的檔案系統只有 套件資料夾 (Package Folder)與應用程式資料資料夾( App Data Folder),若想要存取本機中的 照片、影片、我的文件資料夾,則您需要設定相對應的功能 (Capability),否則,當您存取這些檔案系統的時候,就會產生錯誤。

其中,
套件資料夾 (Package Folder)
可以透過取得 Windows.ApplicationModel.Package.Current.InstalledLocation StorageFolder物件,例如,您可能要針對該App做到可以內建在 OEM 的機器上,並且要存取 StoreManifest.xml 或者 自訂資料 (Custom Data)檔案,這個 StorageFolder 是指向了您的App實際安裝在本機上的目錄路徑。

應用程式資料資料夾( App Data Folder)
Windows.Storage.ApplicationData 是提供對應用程式資料存放區的存取。 應用程式資料是由本機、漫遊或暫時的檔案與設定所組成。
可以該類別透過取得 Windows.Storage.ApplicationData 中的 LocalFolder, RoamingFolder, TemporaryFolder 這三個屬性。

ApplicationData.LocalFolder 取得本機應用程式資料存放區中的根資料夾。
ApplicationData.RoamingFolder 取得漫遊應用程式資料存放區中的根資料夾。
ApplicationData.TemporaryFolder 取得暫存應用程式資料存放區中的根資料夾。

應用程式資料有三個主要類型:
本機:儲存在裝置上,並且跨更新保存。
漫遊:已複製到使用者安裝應用程式的其他裝置。
暫存:隨時可以由系統刪除。

當然,透過應用程式資料資料夾,也可以存取到本機或者漫遊的應用程式設定容器物件。
ApplicationData.LocalSettings 取得本機應用程式資料存放區中的應用程式設定容器。
ApplicationData.RoamingSettings 取得漫遊應用程式資料存放區中的應用程式設定容器。

存取該App中的任何打包的檔案,此時,您就會需要使用到這個套件資料夾,不過,您需要使用 Visual Studio 2013來設定這些資源檔案的類型屬於內容(Content)形式,並且還要設定複製到輸出資料夾內。

如何判斷 StorageFile 或者 StorageFolder 所指向的檔案是否存於 Isolated Storage 內

之前不論在寫 WinRT 或者 Windows Phone App的時候,一定會遇到這樣的需求,那就是想要檢查在 Isolated Storage 內的某個檔案是否存在,並且根據此一結果,決定接下來要怎麼繼續處理。

當然,這樣的需求已經收錄到我自己整理的 Isolated Storage Class Library 內,當作成一個非常好用的 Helper;不過,那個時候所用的方法是:

            try
            {
                if (使用Mutex == true)
                {
                    StorageMutex.WaitOne();
                }
                var file = await folder.GetFileAsync(string.Format("{0}.txt", filename));
                content = await FileIO.ReadTextAsync(file);
            }
            catch (Exception ex)
            {
                Debug.WriteLine(string.Format("Filename:{0}, {1}", filename, ex.ToString()));
            }

使用 GetFileAsync 並且使用異常事件捕捉方法 Try-Catch 將這個方法呼叫予以捕捉,一旦所要讀取的檔案不存在,就會產生異常事件,可以根據這個異常事件(類別 FileNotFoundException)來判斷,是否是由檔案不存在所引起的,不過,這樣的作法太不人道了。

現在有個更好的改善方法可以使用,那就是使用 StorageFile.IsAvailable 屬性來判斷,根據 MSDN 上的說法,StorageFile.IsAvailable 是:如果檔案位於本機、已在本機快取或可供下載,則為 True。否則為 false。您說,使用這個方法是不是更加方便了呢?

另外,在 Windows 8.1,也推出了另外一個相當不錯的方法:StorageFolder.TryGetItemAsync,這個方法為,嘗試使用項目名稱來取得目前資料夾中的單一檔案或子資料夾;在以往,我們需要自己寫個擴充方法來做到

  public static class StorageFolderExtensions
  {
    public static async Task TryGetItemAsync(this StorageFolder folder, 
                                                           string name)
    {
      var files = await folder.GetItemsAsync().AsTask().ConfigureAwait(false);
      return files.FirstOrDefault(p => p.Name == name);
    }
  }

現在,我們只需要簡單的使用下列方法,既可以透過 StorageFolder 物件的 TryGetItemAsync 來判斷出,在該目錄下,這個檔案或者子資料夾是否存在了。

StorageFile file = await ApplicationData.Current.LocalFolder.TryGetItemAsync("test") as StorageFile;
 
if (file != null)
{
}

當然,若您開發的Windows Phone 8.1 App,採用的 Universal App,也可以使用這樣的解決方案喔。

關於檔案的 URI 配置

當要存取某個檔案的時候,我們可以使用ApplicationData Class (提供對應用程式資料存放區的存取。 應用程式資料是由本機、漫遊或暫時的檔案與設定所組成)來取得相對應的 StorageFolder物件,接著依序取得檔案所在位置的目錄 StorageFolder物件,接著取得該目錄下的檔案 StorageFile物件,如此,就可以針對該檔案來進行操作了。

不過,我們可以透過檔案的 URI(統一資源識別元)配置,指出該檔案所在的路徑,我們可以參考這些檔案是來自於 [應用程式套件]、[資料資料夾]或[資源]的應用程式檔案。

ms-appx
配置參考來自應用程式套件的應用程式檔案 (請參閱應用程式套件與部署)。
這類檔案通常為靜態影像、資料、程式碼及配置檔。


        void PopupForSheetMusic_Closed(object sender, object e)
        {
            this.imgSheetMusic.Source = new BitmapImage(new Uri("ms-appx:///Assets/Images/Core/btn_sheet music_n.png"));
        }


        public MyChannelData()
        {
            this.ID = RandomString(20);
            this.OrderNo = 99999;
            this.Title = "";
            this.CreateDatetime = DateTime.Now;
            this.RecordLength = TimeSpan.FromSeconds(0);
            this.GetProductInfo_Data = new GetProductInfo_Response_Data();
            this.RecordingType = Business.RecordingType.VIDEO;
            this.Cover = "ms-appx:///Assets/Images/Core/img_voice_picture.png";
        }


ms-appdata
使用 ms-appdata 配置來參考應用程式檔案,這些檔案來自應用程式的本機、漫遊及暫存資料資料夾。

若想要讀取[本機]、[暫存]、[漫遊]這三個資料夾,可以使用下列的 URI

本機資料夾  ms-appdata:///local/
暫存資料夾  ms-appdata:///temp/
漫遊資料夾  ms-appdata:///roaming/

                    if (xi.Count >= 1)
                    {
                        di.Cover = xi[0].GetProductInfo_Data.ProductCover;
                        di.Cover = string.Format("ms-appdata:///local/CoverImages/{0}.png", xi[0].GetProductInfo_Data.ProductID);
                    }
                    if (xi.Count >= 2)
                    {
                        di.Cover2 = xi[1].GetProductInfo_Data.ProductCover;
                        di.Cover2 = string.Format("ms-appdata:///local/CoverImages/{0}.png", xi[1].GetProductInfo_Data.ProductID);
                    }
                    if (xi.Count >= 3)
                    {
                        di.Cover3 = xi[2].GetProductInfo_Data.ProductCover;
                        di.Cover3 = string.Format("ms-appdata:///local/CoverImages/{0}.png", xi[2].GetProductInfo_Data.ProductID);
                    }


ms-resource

使用 ms-resource 配置來參考應用程式資源,這類資源通常是字串資源。

參考來源:http://msdn.microsoft.com/zh-tw/library/windows/apps/jj655406.aspx

如何在 Windows Store App 與 Windows Phone App上,取得裝置上的唯一 ID 代碼

如何在 Windows Store App 與 Windows Phone App上,取得裝置上的唯一 ID 代碼,相信很多在寫App的朋友都會遇到這樣的問題,我這裡整理出這兩個平台取得裝置上唯一ID代碼 ( Device ID)的方法。

Windows Phone

        public static string GetHardwareId()
        {
            string ss = HostInformation.PublisherHostId;
            return ss;
        }

其中您可以參考 MSDN 上的說明 HostInformation.PublisherHostId property

Windows Store ( WinRT )

        /// 
        /// 取得裝置的唯一識別代碼
        /// 
        /// 
        public static string GetHardwareId()
        {
            var _Token = Windows.System.Profile.HardwareIdentification.GetPackageSpecificToken(null);
            var _Id = _Token.Id;
            var _Reader = Windows.Storage.Streams.DataReader.FromBuffer(_Id);
            var _Bytes = new byte[_Id.Length];
            _Reader.ReadBytes(_Bytes);

            string ss = BitConverter.ToString(_Bytes).Replace("-", "");
            return ss;
        }

其中,在MSDN上的描述為 : HardwareIdentification.GetPackageSpecificToken 取得表示目前硬體的硬體識別項 (ASHWID)。 為每個應用程式封裝傳回的 ASHWID 會不同。換句話說,當這個應用程式開發介面由兩個來自不同封裝的應用程式呼叫時,就會傳回不同的識別項。當同一個封裝的兩個應用程式呼叫它時,它會傳回相同的識別項。

2014/06/24

使用 Windows Phone 的 Facebook App 於寫狀態內容的時候,需要標記好友且好友名字為中文字的作法

當您在使用 Windows Phone 手機,打開 Facebook App,並且要寫最新狀態內容文字的時候,突然想要標記這段文字,指名您的某個 Facebook 好友;不過,若您的好友在Facebook顯示的是中文名字,此如若您輸入 @ 接著使用注音輸入法打入您好有名字的時候,卻發現無法看到自動如下圖紅色框線所標示的您的好友,當然,這個時候,您就無法透過 Facebook App 來標示您的好友了。


若想要解決此一問題,您有兩個做法,一個是使用手寫輸入法,另外一個是使用一般輸入法(如注音輸入法),不過,若您選擇後者的話,需要多幾個步驟要做。


【使用手寫輸入法】


若您的Windows phone 手機上還沒有手寫輸入法,請依照底下說明,啟用手寫輸入法。
》 點選 [設定] 功能,並且選擇 [鍵盤] 選項。
》 在 [設定] >[鍵盤] 畫面中,選擇 [新增鍵盤] 選項
》在 [新增鍵盤] 畫面中,選擇 [中文(繁體) - 手寫] 選項,並且點選最下方的 [確定] 按鈕。
》此時,您剛剛選擇的 中文(繁體) - 手寫 鍵盤就已經可以在您的Windows Phone手機上使用了。

》這個時候,您可以開啟您手機中的 Facebook App,並且點選應用程式列的 [狀態] 按鈕,開始進行輸入您最新的 Facebook 狀態;當您輸入完成您的最新狀態文字之後,可以輸入小老鼠符號 @ 接著,使用手寫輸入法,輸入您好友的名字(姓氏可以不用輸入),如下圖左上方的紅色方塊區域,我們輸入了 @大雅 有好康在這裡,表示想要通知好友 大雅 我的最新狀態。

   接著,請在您的手寫輸入法面板的左下方,如下圖的左下方紅色區域,點選 [繁] 這個按鈕。


》神奇的是,您就會看到您的 Facebook App,可以讓您選擇您好友中,所有 大雅 的好友名單,只要點選您要通知的好友項目,就完成了在寫入最新Facebook狀態內容的時候,也順便標示給您的好友。

在下圖中,我們看到我們要標示的好友為 @大雅,而Facebook App幫我找到了 李大雅 這個好友,我們點選這個好友。

就完成了在寫最新狀態的時候,順便標示好友的需求。

【使用一般輸入法】
接下來的做法,我們不需透過 手寫輸入法 ,也可以做到在更新最新狀態的時候,也可以標示好友的操作方式。

》我們在這裡使用注音輸入法作為示範,我們開啟 Facebook App,並且進入到要寫一個新的Facebook最新狀態的頁面中;接著,把我們要更新的最新狀態文字與需要標示的好友名字都寫出來(記得,只要寫好友的名字,不需要寫全名)。
》接下來,在您的好友名字前面,輸入 小老鼠 符號 @
》這個時候,請將輸入法面板關閉起來,也就是按一下手機上的回上一頁按鈕(通常位於手機顯示面板的最左下方,有個往左的箭頭符號地方)。
》這個步驟也是最神奇的操作,此時,您需要重新點選到您剛剛寫的最新狀態中的任何文字,讓文字輸入法面板可以顯示出來;不過,此時若您還是看不到如下圖畫面中紅色方塊處,您好友的資訊,請切換到英文字的輸入面板(您可以點選左下角的 [繁] 這個文字即可。

神奇的現象發生了,您就會看到您好友的資訊,原來,在注音輸入法的面板中,原本要顯示您好友的資訊的地方,被注音輸入法的智慧提示輸入文字給佔據了,所以,您會看不到您好友的資訊,只要切換到英文輸入面板,就可以看到囉。

若您點選到的文字是英文字,您可切換到數字輸入面板(輸入法面板的左下方的 [&123] 區域,點下去,就可以切換到數字輸入面板了)。

有了這個密技,下次您使用Facebook App就可以在更新您最新狀態文字內容的時候,也可以順便標示您的好友。

在 Windows Phone 多語系應用程式工具組

在您開發 Windows Phone & Windows Store (WinRT) App的時候,若您的App可以支援兩個以上的多國語言文字,必定可以有全球更多的人來認識、安裝、使用,甚至購買您的App;以往要做多國語言支援的時候,需要維護不同語言的資源檔案 .resw,處理起來相當的麻煩,而且,針對不同語系的文字,都需要自己來處理與更新這些文字的翻譯問題。

自從有了 [多語系應用程式工具組] ,這一切的夢厭都隨之煙消雲散了,透過了 [多語系應用程式工具組] ,您可以維護一組語言文字資源,其他的都透過 [多語系應用程式工具組] 幫您來處以,也可協助您使用 Bing 的翻譯工具,自動的翻譯成為不同語系文字,最重要的是,這都是免費的。

最令我激賞的是,這套 [多語系應用程式工具組] 可以支援 Windows Phone & WinRT 的App。

適用於 Visual Studio 2012 的多語系應用程式工具組