XAML in Xamarin.Forms 基礎篇 電子書

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

Xamarin.Forms 快速入門 電子書

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

2017/02/23

Xamarin Cycle 9: 準備注意事項說明

今日,2017.03.23 可以更新到 Xamarin Cycle 9 這個版本,這個版本將會支援 iOS 10.4 & Android 7.1
請參考底下說明,將您的開發環境,調整成為此篇文章說明內容

請安裝 JDK 1.8 x64 版本

現在最新的 JDK 1.8 版的為 8u121

升級 Visual Studio 2015 使用的 Xamarin Toolkit 到 4.3 版本

  • 點選 Visual Studio 2015 功能表 工具 > 選項 > Xamarin > Other > Stable > Check Now
  • 下載完成後,請點選安裝按鈕
  • 今日更新完成後的 Xamarin Toolkit 版本資訊

確認 Xamarin.Android 有使用最新安裝的 JDK

  • 點選 Visual Studio 2015 功能表 工具 > 選項 > Xamarin > Android
  • 找到 Java 開發套件位置,點選變更,切換到 x64 JDK 1.8.0.121 的安裝位置
    C:\Program Files\Java\jdk1.8.0_121

確認 Android SDK 都有安裝與升級到最新版本

  • 點選 Visual Studio 2105 功能表 工具 > Android > Android SDK Manager
  • 確定底下指出的套件,都有安裝與升級到最新版本
    • Tools > Android SDK Tools 25.2.5
    • Tools > Android SDK Platform-tools 25.0.3
    • Tools > Android SDK Build-Tools 25.0.2
    • Android 7.1.1(API 25) > SDK Platform
    • Android 7.0(API 24) > SDK Platform
    • Android 6.0(API 23) > SDK Platform
    • Android 5.1.1(API 22) > SDK Platform
    • Android 5.0.1(API 21) > SDK Platform
    • Android 4.4W.2(API 20) > SDK Platform
    • Android 4.4.2(API 19) > SDK Platform
    • Extras > Android Support Repository 44
    • Extras > Google USB Driver 11

Mac 電腦上也需要同步更新

若您有開發 iOS App,請記得上述的步驟,也需要在 Mac 電腦上都要做一次。
在 Mac 電腦上,您需要更新 Xamarin Studio 到最新版本

2017/02/20

Xamarin FAQ 2-20 : 在ListView中,如何實作出下拉更新的手勢操作

問題

Xamarin.Forms 的 ListView 是否有支援手勢更新的功能,也就是說,當使用者在 ListView 最前面的紀錄是第一筆紀錄的時候,可以使用手指由上往下滑動 ListView,如此,就可以即時更新到最新的資料。

解答

首先,我們先來建立一個頁面,裡面有個 ListView 控制項,看看有那些地方是需要設定的。
在下方的 ListView 標機宣告中,我們使用了
  • IsPullToRefreshEnabled="True"
    設定這個 ListView 需要啟用下拉更新的手勢操作
  • RefreshCommand="{Binding ListView更新資料Command}"
    當 ListView 偵測到您有下拉更新的手勢操作行為時候,這個 RefreshCommand 所綁定的命令,將會被執行;在這個 ICommand 命令中,我們將會更新 DataItemList 的集合資料內容
  • IsRefreshing="{Binding IsBusy}"
    IsRefreshing 將會顯示一個忙碌中的視覺,讓使用者知道 ListView 正在更新資料中,不過,當更新完成資料後,將會設定 IsBusy 的值為 False,這樣,忙碌中的視覺就不會出現了。
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:prism="clr-namespace:Prism.Mvvm;assembly=Prism.Forms"
             prism:ViewModelLocator.AutowireViewModel="True"
             x:Class="XFListViewRefresh.Views.MainPage"
             Title="ListView下拉更新">

    <StackLayout 
      Margin="20"
      HorizontalOptions="Fill" VerticalOptions="Fill">
        <Label Text="{Binding Title}" />
        <ListView
            HorizontalOptions="Fill" VerticalOptions="FillAndExpand"
            ItemsSource="{Binding DataItemList}"
            IsPullToRefreshEnabled="True"
            HasUnevenRows="True"
            RefreshCommand="{Binding ListView更新資料Command}"
            IsRefreshing="{Binding IsBusy}"
            >
            <ListView.ItemTemplate>
                <DataTemplate>
                    <ViewCell>
                        <Grid
                            RowSpacing="0" ColumnSpacing="0"
                            >
                            <Label Text="{Binding DataVale}" />
                        </Grid>
                    </ViewCell>
                </DataTemplate>
            </ListView.ItemTemplate>
        </ListView>
    </StackLayout>
</ContentPage>
要進行下拉更新命令的時候,可以類似底下的處理動作。
            ListView更新資料Command = new DelegateCommand(() =>
            {
                IsBusy = true;
                Refresh();
                IsBusy = false;
            });
Xamarin-跨平台手機應用程式設計入門-粉絲團

Xamarin Button 的 Command / CommandParameter 綁定與 IsEnabled 的問題測試

在這個範例中,我們需要來進行測試這個需求:
對於 Button 按鈕,我們需要使用 Command 來綁定 ViewModl 上的 ICommand 的物件,並且需要使用 CommandParameter 取得當時綁定的物件內容,而且,需要使用 ViewModel 內的某個屬性,綁定到這個按鈕上的 IsEnabled 屬性,這是要做到可以透過 ViewModel 來控制這個按鈕是否可以使用。
不過,在 Xamarin.Forms 中,若您是在底下的情境,上述的動作將會失敗。
這在這使用情境中,我們使用了 Source 來指定需要綁定物件的來源,並且,CommandParameter 使用了 Binding . 來綁定當時的物件;在這個情況之下,這個 XAML 中的 IsEnable 屬性綁定就會失敗,這個屬性值永遠為 True。
        <Button 
            Text="3 命令綁定、CmdPara(.)、Source"
            Command="{Binding Path=BindingContext.按鈕命令綁定測試Command, Source={x:Reference ThisPage}}"
            CommandParameter="{Binding .}"
            IsEnabled="{Binding 按鈕命令綁定測試狀態}"/>
想要解決這個問題,需要使用 System.Windows.Input.ICommand 提供的 CanExecute 委派方法來解決。

專案原始碼

執行範例

2017/02/19

Xamarin FAQ 2-19 : 在ListView中,如何根據紀錄類型,顯示出不同的樣貌(資料樣板選擇器)

問題

在 Xamarin.Forms中,有個 DataTemplateSelector (資料樣板選擇器),請問這是甚麼類別,用來做甚麼用途的呢?

解答

測試範例專案原始碼
在ListView中,若我們想要根據紀錄類型,顯示出不同的樣貌,此時,並不是在 ViewModel 中做處理,而是我們是先定義了多個資料樣板,我們想要透過 DataTemplateSelector (資料樣板選擇器)來根據當時的資料內容,自動幫我們選擇合適的資料樣板;如此,ListView 就可以根據每筆紀錄的內容,顯示出不同的視覺效果了。
在底下的 XAML 範例中,我們在 ContentPage.Resources 中定義了兩個資料樣板 validPersonTemplate / invalidPersonTemplate,另外,也宣告了一個 local:PersonDataTemplateSelector 物件,這個物件是我們自行定義的一個類別,用來根據當時的資料內容,自動傳回合適的資料樣板。
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:prism="clr-namespace:Prism.Mvvm;assembly=Prism.Forms"
             xmlns:local="clr-namespace:XFSelector"
             prism:ViewModelLocator.AutowireViewModel="True"
             x:Class="XFSelector.Views.HasSelectorPage">

    <ContentPage.Resources>
        <ResourceDictionary>
            <DataTemplate x:Key="validPersonTemplate">
                <ViewCell>
                    <Grid>
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="0.4*" />
                            <ColumnDefinition Width="0.3*" />
                            <ColumnDefinition Width="0.3*" />
                        </Grid.ColumnDefinitions>
                        <Label Text="{Binding Name}" TextColor="Green" FontAttributes="Bold" />
                        <Label Grid.Column="1" Text="{Binding DateOfBirth, StringFormat='{0:d}'}" TextColor="Green" />
                        <Label Grid.Column="2" Text="{Binding Location}" TextColor="Green" HorizontalTextAlignment="End" />
                    </Grid>
                </ViewCell>
            </DataTemplate>
            <DataTemplate x:Key="invalidPersonTemplate">
                <ViewCell>
                    <Grid>
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="0.4*" />
                            <ColumnDefinition Width="0.3*" />
                            <ColumnDefinition Width="0.3*" />
                        </Grid.ColumnDefinitions>
                        <Label Text="{Binding Name}" TextColor="Red" FontAttributes="Bold" />
                        <Label Grid.Column="1" Text="{Binding DateOfBirth, StringFormat='{0:d}'}" TextColor="Red" />
                        <Label Grid.Column="2" Text="{Binding Location}" TextColor="Red" HorizontalTextAlignment="End" />
                    </Grid>
                </ViewCell>
            </DataTemplate>
            <local:PersonDataTemplateSelector 
                x:Key="personDataTemplateSelector" 
                ValidTemplate="{StaticResource validPersonTemplate}" 
                InvalidTemplate="{StaticResource invalidPersonTemplate}" />
        </ResourceDictionary>
    </ContentPage.Resources>

    <StackLayout Padding="20">
        <Label Text="有使用資料樣板選擇器" FontAttributes="Bold" HorizontalOptions="Center" />
        <ListView 
            ItemsSource="{Binding People}"
            ItemTemplate="{StaticResource personDataTemplateSelector}" />
    </StackLayout>
</ContentPage>
接下來,我們來看看 PersonDataTemplateSelector 這個類別要如何定義呢?首先,需要繼承 DataTemplateSelector 這個類別,並且要定義 OnSelectTemplate 這個方法,而我們就會在 OnSelectTemplate 這個方法內,依據當時紀錄的內容,決定要使用哪個資料樣板。
    /// <summary>
    /// 依據出生日期年分,決定要顯示哪種資料樣板
    /// </summary>
    public class PersonDataTemplateSelector : DataTemplateSelector
    {
        // 這個物件值,將會在 XAML 中來定義
        public DataTemplate ValidTemplate { get; set; }

        // 這個物件值,將會在 XAML 中來定義
        public DataTemplate InvalidTemplate { get; set; }

        protected override DataTemplate OnSelectTemplate(object item, BindableObject container)
        {
            // 根據當時物件的值,決定要使用哪個資料樣板
            return ((Person)item).DateOfBirth.Year >= 1980 ? ValidTemplate : InvalidTemplate;
        }
    }
Xamarin-跨平台手機應用程式設計入門-粉絲團

Xamarin FAQ 2-18 : 在ListView中,如何根據紀錄類型,顯示出不同的樣貌(簡單方法)

問題

繼續 Xamarin FAQ 2-17的問題,這個時候,若每筆紀錄要出現的內容或者格式,想要依據當時的資料內容,進行變更要顯示的資料格式或者內容,這個時候,可以使用哪種技術呢?

解答

這個問題,一樣可以有多種技術可以選擇,在這裡,我們使用了在 ViewModel 中來處理;主要的設計方法為,我們需要在 ViewModel 內加入一些其他屬性,這些屬性的內容會依據當時的資料內容,進行動態的調整其物件值。在底下的 XAML 中,我們希望每筆紀錄中,當紀錄資料的出生入其大於等於1980,則文字顏色要設定成為 綠色,否則,文字顏色要設定成為 紅色。因此,每個文字的顏色,並不是固定顏色值,而是綁定 ViewModel 內的某個屬性。
        <ListView 
            ItemsSource="{Binding People}"
            >
            <ListView.ItemTemplate>
                <DataTemplate >
                    <ViewCell>
                        <Grid>
                            <Grid.ColumnDefinitions>
                                <ColumnDefinition Width="0.4*" />
                                <ColumnDefinition Width="0.3*" />
                                <ColumnDefinition Width="0.3*" />
                            </Grid.ColumnDefinitions>
                            <Label Text="{Binding Name}" TextColor="{Binding ShowColor}" FontAttributes="Bold" />
                            <Label Grid.Column="1" Text="{Binding DateOfBirth, StringFormat='{0:d}'}" TextColor="{Binding ShowColor}" />
                            <Label Grid.Column="2" Text="{Binding Location}" TextColor="{Binding ShowColor}" HorizontalTextAlignment="End" />
                        </Grid>
                    </ViewCell>
                </DataTemplate>
            </ListView.ItemTemplate>
        </ListView>
在 ViewModel 中,當這個頁面要顯示之前,ViewModel 的 OnNavigatedTo 方法會被執行,此時,我們將會進行要顯示在 ListView 內所有物件的值,就在此時,我們判斷每筆紀錄的生日欄位,若出生年份大於 1980,則會設定 ShowColor 這個屬性值為綠色,否則,設定為紅色。經過這樣處理,ListView 內的每筆紀錄文字,就會顯示不同的顏色了。
        public void OnNavigatedTo(NavigationParameters parameters)
        {
            People = new ObservableCollection<Person> {
                new Person ("Kath", new DateTime (1985, 11, 20), "France"),
                new Person ("Steve", new DateTime (1975, 1, 15), "USA"),
                new Person ("Lucas", new DateTime (1988, 2, 5), "Germany"),
                new Person ("John", new DateTime (1976, 2, 20), "USA"),
                new Person ("Tariq", new DateTime (1987, 1, 10), "UK"),
                new Person ("Jane", new DateTime (1982, 8, 30), "USA"),
                new Person ("Tom", new DateTime (1977, 3, 10), "UK")
            };

            foreach (var item in People)
            {
                if(item.DateOfBirth.Year >= 1980)
                {
                    item.ShowColor = Color.Green;
                }
                else
                {
                    item.ShowColor = Color.Red;
                }
            }
        }
Xamarin-跨平台手機應用程式設計入門-粉絲團