XAML in Xamarin.Forms 基礎篇 電子書

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

Xamarin.Forms 快速入門 電子書

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

2014/07/01

在 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/29

好用的 XAML 資料繫結 Data Binding 的轉換器 Converter > 字串為空值 Visibility

當我們使用 XAML 資料繫結 Data Binding的時候,透過轉換器 Converter,可以很容易地透過來源資料 Source Data 的數據值,直接控制或者影響 XAML 控制項 (Element)的顯示特性或者顯示內容。

底下是我常用的一個轉換器(Converter),當來源資料的欄位為字串類型的時候,並且該字串的為空字串,這個時候,該轉換器會回傳 Visibility.Visible 或者 Visibility.Collapsed ,這樣,就可以控制項是否要顯示出來。

這樣的轉換器通常我會用於:若主題或者說明文字不存在的時候,不要顯示相對應的按鈕或者圖片,是個相當好用的轉換器


public sealed class EmptyStringToVisibilityConverter : IValueConverter
{
    public object Convert(object valueType targetTypeobject parameterstring language)
    {
        return (value is string && (string)value != ""? Visibility.Visible : Visibility.Collapsed;
    }
 
    public object ConvertBack(object valueType targetTypeobject parameterstring language)
    {
        return value is Visibility && (Visibility)value == Visibility.Visible;
    }
}


最後,記得當要在某個頁面中使用該轉換器的時候,要加入該轉換器當時的命名空間 namespace 宣告,並且定義該轉換器成為可用的 Key
<Converters:EmptyStringToVisibilityConverter x:Key="EmptyStringToVisibilityConverter"/>


<ResourceDictionary
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:VulcanApp.Common"
    xmlns:Converters="using:VulcanApp.Converters"     
     xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
    mc:Ignorable="d">
    <Converters:EmptyStringToVisibilityConverter x:Key="EmptyStringToVisibilityConverter"/>

好用的 XAML 資料繫結 Data Binding 的轉換器 Converter > bool Visibility

當我們使用 XAML 資料繫結 Data Binding的時候,透過轉換器 Converter,可以很容易地透過來源資料 Source Data 的數據值,直接控制或者影響 XAML 控制項 (Element)的顯示特性或者顯示內容。

底下是我常用的一個轉換器(Converter),當來源資料的欄位值為 True 或者 False 的布林值的時候,該轉換器會回傳 Visibility.Visible 或者 Visibility.Collapsed ,這樣,就可以控制項是否要顯示出來。


public class BooleanToVisibilityConverter : IValueConverter
{
    public object Convert(object valueType targetTypeobject parameterstring language)
    {
        return (value is bool && (bool)value == true? Visibility.Visible : Visibility.Collapsed;
    }
 
    public object ConvertBack(object valueType targetTypeobject parameterstring language)
    {
        return value is Visibility && (Visibility)value == Visibility.Visible;
    }
}

最後,記得當要在某個頁面中使用該轉換器的時候,要加入該轉換器當時的命名空間 namespace 宣告,並且定義該轉換器成為可用的 Key
<Converters:BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter"/>


<ResourceDictionary
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:VulcanApp.Common"
    xmlns:Converters="using:VulcanApp.Converters"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
    mc:Ignorable="d">
    <Converters:BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter"/>


2014/06/28

將 Windows 8.1 Store App 透過 Sideload 側載 方式,安裝到您企業內部使用者電腦上

Windows 8.1 的 WinRT Stroe App 與傳統的桌面程式,有著明顯不同的特性,其實,對於程式開發者而言,採用 WinRT Store 架構來開發的App,真的比起傳統的桌面App方便了許多,因為:它是全螢幕的、擁有良好的App運作流程、不會破壞到作業系統與影響其安全運作、可以觸控操作、流暢的表現和互動式的動畫。

單純開發Windows 8.1 Store App,也許不會太困難,因為,只要您具有 C# / VB / JavaScript / C++,立馬就可以馬上來開發,甚至開發出不錯的App;可是,大部分開發出來的App,都會提交到 Windows Store 市集做認證,一旦通過審核,就會在市集的App上,看到您開發出來的App,而使用者就可以透過市集App,下載並且安裝您開發出來的App到他們的電腦上。

可是,當您想要開發 Windows 8.1 Store App,並且想要將這個App (例如 line-of-business LOB 類型)讓企業內部的電腦使用,不過,您不想要透過微軟官方的市集來讓使用者從市集App找到專屬於您企業的App,甚至從市集下載您專屬App到企業員工的電腦上,這可就傷腦精了;因為,到現在為止,微軟並沒有針對 Windows 8.1 平台,推出各企業專屬的市集App,也就是說,想要把您開發出來,並且專屬於自己企業的Windows Store App到企業內部員工的電腦上,就不是這麼簡單的過程,這需要花點時間來處理。

想要佈署Windows 8.1 Store App到使用者的電腦上,而不透過微軟官方的公開市集系統,您可以採用的是 [側載] Sideloading 技術 (側載的應用程式不需要發行到 Windows 市集,也不需要使用已註冊的 Windows 市集開發人員帳戶就能開發。),讓您可以輕鬆地做到這樣的需求。

側載是個方法,可以讓您安裝 Windows Store App到電腦上,但是不透過市集App,這樣,就有幾個問題要考量:

  1. 開發出您企業專屬的 Windows Store App
  2. 如何將App的程式,自動佈署到使用者的電腦上
  3. 如何將這些App程式,安裝到使用者電腦上
  4. 如何進行新版本的App升級

開發出您企業專屬的 Windows Store App
這個部分與您開發可以上傳到微軟市集上的App的技術一樣,差別在於,您的App不需要透過微軟官方的測試與審核,因此,您需要自己透過內建工具來做App相容性的測試,與自己確保App的執行品質與效能。

不過,若是要將 LOB 類型的App透過側載的方式安裝到企業內部電腦上,您所開發的App,需要安裝與設定您企業內部發出的憑證,這個明證並不一定要在信任的憑證授權單位的跟目錄上,只要讓企業內部使用者的電腦可以信任該憑證即可。如果憑證來自於其中一個已經信任的授權單位,您就不需要在目標電腦上部署和管理額外的憑證。

另外要注意的是,若您開發的Windows 8.1 Store App有使用了 Windows 推播通知服務 (WNS) 等功能,則您需要使用 Windows 市集的儀表板,來為該應用程式保留名稱,並且要將您這個應用程式與市集上所指派的發行者名稱產生關聯,而且也要受到您電腦的信任。

如何將App的程式,自動佈署到使用者的電腦上
這裡有著許多來自於微軟的技術、甚至於還有很多第三方的產品可以選擇;微軟這裡也提供了一些需要付費或者免費的解決方案:Windows PowerShell, Microsoft Deployment Toolkit (MDT), System Center Configuration Manager, Windows Intune,至於這些功能是如何、甚至於如何運作,這需要請您們管理 AD Domain 的 IT 技術人員協助您來處理這些需求,畢竟這些範疇不是會寫程式的人,就會處理的。

如何將這些App程式,安裝到使用者電腦上
您企業內部的使用想要享受到側載的功能,必須是 Windows 8.1 Enterprise 企業版 或者是 Professional 專業版,並且要能夠加入網域;這樣您就可以透過群組原則 Group Policy 來設定這些電腦 網域群組原則物件 (GPO),可以接受並安裝,不是來自於市集的 Windows 8.1 Store App (允許安裝信任的應用程式)。

不過,若想要讓其他類型的Windows 8.1作業系統,例如 Windows RT 版本、Professional 專業版,您需要額外購買啟用可以側載的產品金鑰,以便進行企業側載。

要啟用側載產品金鑰,請以系統管理員權限,開啟命令提示字元,然後輸入下列命令來新增側載產品金鑰。

Slmgr /ipk <側載產品金鑰>

輸入下列命令來啟用側載金鑰:
slmgr /ato ec67814b-30e6-4a50-bf7b-d55daf729d1e

另外,我們還需要做到設定有開發人員授權的企業電腦

在電腦中,針對要套用群組原則設定的網域群組原則物件 (GPO) 開啟群組原則管理編輯器,如下方所指定。

  • 按一下以展開 [電腦設定]、[系統管理範本]、[Windows 元件] 及 [應用程式套件部署]。
  • 按兩下 [允許在沒有安裝開發人員授權情況下開發 Windows 市集應用程式] 設定。
  • 在 [允許在沒有安裝開發人員授權情況下開發 Windows 市集應用程式] 視窗中,按一下 [啟用],然後按一下 [確定]。
  • 按兩下 [允許安裝所有信任的應用程式] 設定。
  • 在 [允許安裝所有信任的應用程式] 視窗中,按一下 [啟用],然後按一下 [確定]。

將群組原則設定為允許在沒有安裝開發人員授權情況下開發 Windows 市集應用程式,下列登錄設定會更新為:HKEY_LOCAL_MACHINE\Software\Policies\Microsoft\Windows\Appx\AllowDevelopmentWithoutDevLicense = 1
將群組原則設定成允許信任的應用程式後,會更新下列登錄設定:HKEY_LOCAL_MACHINE\Software\Policies\Microsoft\Windows\Appx\AllowAllTrustedApps = 1

最後,可以使用 Windows PowerShell 或者任何支援執行 PowerShell指令碼或者Cmdlet的管理工具,在 PowerShell 命令提示字元中輸入底下文字,就可以進行您開發的App,並且側載到使用者電腦上了

add-appxpackage C:\YourEnterprise\YourStoreApp.appx

如何進行新版本的App升級
對於這個問題,是比較棘手的,若您的App是透過市集安裝的,使用者可以透過市集App來了解到他們已經從市集下載、安裝的App,有哪些App已經推出了新版本;使用者只需要透過市集App就可以直接升級這個App到最新版本。若是採用側載方式,則還是需要使用上述的方式來進行,並且我們可能也需要在App中,實作是否有新的版本推出機制。




如何在 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) ),使用 [裝置] 視窗來調整您設計時期的頁面螢幕轉向,如下圖所示的紅色方框,左邊的圖示就是讓您的設計時期的手機螢幕轉向成為橫式,而右邊的圖示,就是可以將您設計時期的頁面轉向成為直式。








為什麼無法在 C# 中,同時使用 static 與 const 呢?

其實,原因十分簡單,那就是,所有的常數 (constants),要使用 const 來標示,而且,常數暗示就是靜態 (static) 特性,因此,您無法在宣告嘗試成員的時候,也用 static 來標示。