XAML in Xamarin.Forms 基礎篇 電子書

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

Xamarin.Forms 快速入門 電子書

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

2017/02/20

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-跨平台手機應用程式設計入門-粉絲團

2017/02/17

Xamarin FAQ 2-17 : 如何客製化ListView的每筆紀錄視覺

問題

ListView 除了 TextCell / ImageCell 這兩種預設的紀錄顯示方式,若想要自行定義每筆 ListView 的紀錄所顯示的資料樣式,例如,想要加入 Switch / 按鈕到每筆紀錄上,這個時候,有甚麼解法呢?

解答

Xamarin.Forms 中的 ListView 控制項中,除了上述兩種樣式可以選擇之外,還可以使用 ViewCell 來定義每筆紀錄要顯示的資料格式;例如,在底下的範例中,我們在 ItemTemplate > DataTemplate 內,使用了 ViewCell 來定義每筆紀錄要出現的樣貌。
在這裡,我們定義了一個 Grid 版面配置,在這個裡面分別定義了三個欄位,因此,我們可以在這三個欄位中,分別指定要顯示那些資料。
        <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="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>
            </ListView.ItemTemplate>
        </ListView>
Xamarin-跨平台手機應用程式設計入門-粉絲團

2017/02/16

Xamarin FAQ 2-16 : 在ListView內,使用彈出功能表但綁定同一個命令,要如何區分來自哪個項目

問題

在開發過程中,想要使用一個 ICommand 物件,來綁定 ListView 的多個彈出功能表項目,但是,要能夠讓 ICommand 命令可以知道哪個命令按鈕被按下了,該如何設計呢?

解答

這個時候,可以使用 CommandParameter 這個屬性,來標示出單要執行 ICommand 命令的時候,透過 CommandParameter 可以區分當時按下的按鈕是哪個,並且根據 CommandParameter 的內容,進行不同的處理。
                    <ViewCell>
                        <ViewCell.ContextActions>
                            <MenuItem Text="立即產生"
                                      Command="{Binding 右鍵功能表Command}" CommandParameter="立即產生"  />
                            <MenuItem Text="刪除"
                                      Command="{Binding 右鍵功能表Command}" CommandParameter="刪除"
                                      IsDestructive="True" />
                        </ViewCell.ContextActions>
Xamarin-跨平台手機應用程式設計入門-粉絲團

2017/02/15

Xamarin FAQ 2-15 : 在ListView內,如何使用彈出功能表

問題

很多App都可以在 ListView 上製作出類似 Windows 右鍵彈出功能表的效果,那麼,若想要使用 Xamarin.Forms 來開發,是否可以做到這樣的功能呢?

解答

其實,在 Xamarin.Forms 中,已經具備了這樣功能,您可以在 ViewCell 內,只用這個 ViewCell.ContextActions Property Element 表示方式,使用 MenuItem 標記來宣告,當使用者要使用彈出功能錶的時候,要出現甚麼樣的選項內容。
在底下的範例中,會出現兩個選項,若使用者選擇了某個選項,則會執行相對應 ViewModel 內的 ICommand 命令。
                    <ViewCell>
                        <ViewCell.ContextActions>
                            <MenuItem Text="立即產生"
                                      Command="{Binding 立即產生Command}" CommandParameter="{Binding .}"  />
                            <MenuItem Text="刪除"
                                      Command="{Binding 刪除Command}" CommandParameter="{Binding .}"
                                      IsDestructive="True" />
                        </ViewCell.ContextActions>
Xamarin-跨平台手機應用程式設計入門-粉絲團