XAML in Xamarin.Forms 基礎篇 電子書

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

Xamarin.Forms 快速入門 電子書

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

2016/11/03

Xamarin.Forms SQLite資料庫使用

在這個範例專案中,將會說明如何在核心PCL專案內,使用 SQLite 資料庫來操作資料表的 CRUD功能。您需要在原生專案與核心PCL專案中安裝這個 SQLite.Net PCL NuGet 套件,並且要在原生專案中提供 SQLiteConnection 的實作。

建立SQLite資料庫使用方案

  1. 首先,開啟您的 Visual Studio 2015
  2. 接著透過 Visual Studio 2015 功能表,選擇這些項目 檔案 > 新增 > 專案 準備新增一個專案。
  3. 接著,Visual Studio 2015 會顯示 新增專案 對話窗,請在這個對話窗上,進行選擇 Visual C# > Cross-Platform > Blank Xaml App (Xamarin.Forms Portable)
  4. 接著,在最下方的 名稱 文字輸入盒處,輸入 XFSQLite 這個名稱,最後使用滑鼠右擊右下方的 確定按鈕。
  5. 當專案建立到一半,若您的開發環境還沒有建置與設定完成 Mac 電腦與 Xamarin Studio for Mac 系統,此時會看到 Xamarin Mac Agent Instructions 對話窗出現,這個對話窗是要提醒您進行與 Mac 電腦連線設定,這是因為,您無法在 Windows 作業系統進行 iOS 相關應用程式的建立與設計工作,而是需要透過 Mac 電腦安裝的 XCode 來協助您完成這些 iOS 應用程式的建立工作。不過,這不影響您繼續開發 Xamarin.Forms 的應用程式,只不過此時,您無法編譯與執行 iOS 的應用程式。
  6. 接著會看到 新的通用Windows專案 對話視窗,此時,您只需要按下 確定 按鈕即可,此時,專案精靈會繼續完成相關平台的專案建立工作。
  7. 最後,整個新的 Xamarin.Forms 專案就建立完成了。

安裝所需 NuGet 套件

  1. 請在 XFSQLite 核心PCL專案的 參考 節點上,滑鼠右擊,接著點選 管理 NuGet 套件 選項,接著點選 瀏覽 標籤頁次,在搜尋文字輸入盒中,輸入 SQLite.Net PCL 這個套件,當找到這個套件之後,請將這個套件安裝到這個專案裡面。
  2. 請在 XFSQLite.Droid 專案的 參考 節點上,滑鼠右擊,接著點選 管理 NuGet 套件 選項,接著點選 瀏覽 標籤頁次,在搜尋文字輸入盒中,輸入 SQLite.Net PCL 這個套件,當找到這個套件之後,請將這個套件安裝到這個專案裡面。
  3. 請在 XFSQLite.iOS 專案的 參考 節點上,滑鼠右擊,接著點選 管理 NuGet 套件 選項,接著點選 瀏覽 標籤頁次,在搜尋文字輸入盒中,輸入 SQLite.Net PCL 這個套件,當找到這個套件之後,請將這個套件安裝到這個專案裡面。
  4. 請在 XFSQLite.UWP 專案的 參考 節點上,滑鼠右擊,接著點選 管理 NuGet 套件 選項,接著點選 瀏覽 標籤頁次,在搜尋文字輸入盒中,輸入 SQLite.Net PCL 這個套件,當找到這個套件之後,請將這個套件安裝到這個專案裡面。
請特別注意,當您在安裝 sqlite-net-pcl NuGet 套件的時候,將會發現到很多類似的名稱的套件,請您要選取底下的套件
Created by: Frank A. Krueger
Id: sqlite-net-pcl
NuGet link: sqlite-net-pcl
sqlite-net-pcl

核心PCL專案

建立 SQLite 使用的介面

  1. 滑鼠右擊 XFSQLite 核心PCL專案節點,選擇 加入 > 新增項目 > Visual C# > 介面
  2. 在底下名稱欄位,輸入 ISQLite 並且點選 新增 按鈕
  3. 使用底下程式碼替換掉剛剛產生的檔案

ISQLite.cs

using SQLite;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace XFSQLite
{
    public interface ISQLite
    {
        SQLiteConnection GetConnection();
    }
}

建立資料表的模型

  1. 滑鼠右擊 XFSQLite 核心PCL專案節點,選擇 加入 > 類別 > Visual C# > 類別
  2. 在底下名稱欄位,輸入 MyRecord 並且點選 新增 按鈕
  3. 使用底下程式碼替換掉剛剛產生的檔案

MyRecord.cs

using SQLite;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace XFSQLite
{
    public class MyRecord
    {
        public MyRecord()
        {
        }

        [PrimaryKey, AutoIncrement]
        public int ID { get; set; }
        public string UserName { get; set; }
        public string SelectItem { get; set; }
        public bool Done { get; set; }
    }
}

建立資料庫類別

  1. 滑鼠右擊 XFSQLite 核心PCL專案節點,選擇 加入 > 類別 > Visual C# > 類別
  2. 在底下名稱欄位,輸入 DoggyDatabase 並且點選 新增 按鈕
  3. 使用底下程式碼替換掉剛剛產生的檔案

DoggyDatabase.cs

using SQLite;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xamarin.Forms;

namespace XFSQLite
{
    public class DoggyDatabase
    {
        static object locker = new object();

        public string DBPath { get; set; }

        SQLiteConnection database;

        public DoggyDatabase()
        {
            database = DependencyService.Get<ISQLite>().GetConnection();
            DBPath = database.DatabasePath;
            // create the tables
            database.CreateTable<MyRecord>();
        }

        public IEnumerable<MyRecord> GetItems()
        {
            lock (locker)
            {
                return (from i in database.Table<MyRecord>() select i).ToList();
            }
        }

        public IEnumerable<MyRecord> GetItemsNotDone()
        {
            lock (locker)
            {
                return database.Query<MyRecord>("SELECT * FROM [MyRecord] WHERE [Done] = 0");
            }
        }

        public MyRecord GetItem(int id)
        {
            lock (locker)
            {
                return database.Table<MyRecord>().FirstOrDefault(x => x.ID == id);
            }
        }

        public int SaveItem(MyRecord item)
        {
            lock (locker)
            {
                if (item.ID != 0)
                {
                    database.Update(item);
                    return item.ID;
                }
                else
                {
                    return database.Insert(item);
                }
            }
        }

        public int DeleteItem(int id)
        {
            lock (locker)
            {
                return database.Delete<MyRecord>(id);
            }
        }

        public void DeleteAll()
        {
            var fooItems = GetItems().ToList();
            foreach (var item in fooItems)
            {
                DeleteItem(item.ID);
            }
        }
    }
}

修正首頁頁面

  1. 在 XFSQLite 核心PCL專案內,打開 `MainPage.xaml
  2. 使用底下XAML宣告標記換掉這個檔案內容

MainPage.xaml

<?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:local="clr-namespace:XFSQLite"
             x:Class="XFSQLite.MainPage">

  <StackLayout
    Orientation="Vertical"
    VerticalOptions="Center" HorizontalOptions="Center"
    >
    <Label
      x:Name="labelMessage"
      Text="歡迎來到 SQLite 的世界"
      VerticalOptions="Center"
      HorizontalOptions="Center" />

    <Label
      x:Name="labelMessagePath"
      Text=""
      VerticalOptions="Center"
      HorizontalOptions="Center"
      LineBreakMode="WordWrap"/>

    <Label
     x:Name="labelMessageWrite"
     Text=""
     VerticalOptions="Center"
     HorizontalOptions="Center" />

    <Button
      x:Name="button寫入資料庫"
      Text="寫入資料庫" />

    <Label
     x:Name="labelMessageRead"
     Text=""
     VerticalOptions="Center"
     HorizontalOptions="Center" />

    <Button
      x:Name="button從資料庫讀出"
      Text="從資料庫讀出" />
  </StackLayout>

</ContentPage>
  1. 在 XFSQLite 核心PCL專案內,打開 `MainPage.xaml.cs
  2. 使用底下程式碼替換掉剛剛產生的檔案

MainPage.xaml.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xamarin.Forms;

namespace XFSQLite
{
    public partial class MainPage : ContentPage
    {
        DoggyDatabase fooDoggyDatabase;
        public MainPage()
        {
            InitializeComponent();

            fooDoggyDatabase = new DoggyDatabase();

            labelMessagePath.Text = $"路徑: {fooDoggyDatabase.DBPath}";

            button寫入資料庫.Clicked += (s, e) =>
            {
                fooDoggyDatabase.DeleteAll();
                fooDoggyDatabase.SaveItem(new MyRecord
                {
                    UserName = "Vulcan Lee",
                    SelectItem = "一顆蘋果",
                    Done = false,
                });
                labelMessageWrite.Text = $"資料已經寫入資料表內";
            };
            button從資料庫讀出.Clicked += (s, e) =>
            {
                var fooItem = fooDoggyDatabase.GetItems().FirstOrDefault();

                labelMessageRead.Text = $"從資料表內讀取: {fooItem.UserName} / {fooItem.SelectItem}";
            };
        }
    }
}

原生 Android 專案

建立 SQLite 使用的介面

  1. 滑鼠右擊 XFSQLite.Droid 核心PCL專案節點,選擇 加入 > 類別 > Visual C# > Class
  2. 在底下名稱欄位,輸入 SQLite_Android 並且點選 新增 按鈕
  3. 使用底下程式碼替換掉剛剛產生的檔案

SQLite_Android.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using Xamarin.Forms;
using XFSQLite.Droid;
using System.IO;

[assembly: Dependency(typeof(SQLite_Android))]
namespace XFSQLite.Droid
{
    public class SQLite_Android : ISQLite
    {
        public SQLite_Android()
        {
        }

        #region ISQLite implementation
        public SQLite.SQLiteConnection GetConnection()
        {
            var sqliteFilename = "DoggyDB.db3";
            string documentsPath = System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal); // Documents folder
            var path = Path.Combine(documentsPath, sqliteFilename);

            var conn = new SQLite.SQLiteConnection(path);

            // Return the database connection 
            return conn;
        }
        #endregion
    }
}

原生 iOS 專案

建立 SQLite 使用的介面

  1. 滑鼠右擊 XFSQLite.iOS 核心PCL專案節點,選擇 加入 > 類別 > Apple > 類別
  2. 在底下名稱欄位,輸入 SQLite_iOS 並且點選 新增 按鈕
  3. 使用底下程式碼替換掉剛剛產生的檔案

SQLite_iOS.cs

using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using Xamarin.Forms;
using XFSQLite.iOS;

[assembly: Dependency(typeof(SQLite_iOS))]
namespace XFSQLite.iOS
{
    public class SQLite_iOS : ISQLite
    {
        public SQLite_iOS()
        {
        }

        #region ISQLite implementation
        public SQLite.SQLiteConnection GetConnection()
        {
            var sqliteFilename = "DoggyDB.db3";
            string documentsPath = Environment.GetFolderPath(Environment.SpecialFolder.Personal); // Documents folder
            string libraryPath = Path.Combine(documentsPath, "..", "Library"); // Library folder
            var path = Path.Combine(libraryPath, sqliteFilename);

            var conn = new SQLite.SQLiteConnection(path);

            // Return the database connection 
            return conn;
        }
        #endregion
    }
}

原生 UWP 專案

建立 SQLite 使用的介面

  1. 滑鼠右擊 XFSQLite.UWP 核心PCL專案節點,選擇 加入 > 類別 > Visual C# > 類別
  2. 在底下名稱欄位,輸入 SQLite_UWP 並且點選 新增 按鈕
  3. 使用底下程式碼替換掉剛剛產生的檔案

SQLite_UWP.cs

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Windows.Storage;
using Xamarin.Forms;
using XFSQLite.UWP;

[assembly: Dependency(typeof(SQLite_UWP))]
namespace XFSQLite.UWP
{
    public class SQLite_UWP : ISQLite
    {
        public SQLite_UWP()
        {
        }
        #region ISQLite implementation
        public SQLite.SQLiteConnection GetConnection()
        {
            var sqliteFilename = "DoggyDB.db3";
            string path = Path.Combine(ApplicationData.Current.LocalFolder.Path, sqliteFilename);

            var conn = new SQLite.SQLiteConnection(path);

            // Return the database connection 
            return conn;
        }
        #endregion
    }
}

實際執行畫面

Android 執行結果

請在方案總管內,滑鼠右擊 XFAuth.Droid 專案,選擇 設定為起始專案,接著按下 F5 開始執行。
Android執行結果1

iOS 執行結果

請在方案總管內,滑鼠右擊 XFAuth.iOS 專案,選擇 設定為起始專案,接著按下 F5 開始執行。
iOS執行結果1

UWP 執行結果

請在方案總管內,滑鼠右擊 XFAuth.iOS 專案,選擇 設定為起始專案,接著按下 F5 開始執行。
UWP執行結果1

在 Xamarin.Forms 中使用動畫效果

想要在 Xamarin.Forms 內,讓在 XAML 內控制項可以做出動畫效果,原則上,需要透過 Code Behind 的方式來做到動畫,除非你需要透過 Behavior 的方式把這些動畫特效,透過 XAML 宣告與資料繫結的方式來做出動畫效果。
若要依據執行動畫,可以使用底下方式來驅動。
            await button.TranslateTo(200, 0, 1000);
            await button.TranslateTo(0, 100, 1000);
            await button.ScaleTo(2.0, 1000);
            await button.RotateTo(360, 1000);
想要同時執行動畫,可以使用底下方式來驅動。
            await Task.WhenAll(
                button.TranslateTo(200, 0, 1000),
                button.TranslateTo(0, 100, 1000),
                button.ScaleTo(2.0, 1000),
                button.RotateTo(360, 1000));
專案原始碼

2016/11/02

如何在 Mac 電腦上安裝其他的 iOS Simulator

在 Mac 電腦上,開啟 Xcode 程式。

在功能表上,點選 [Xcode] > [Preferences] > [Components]

在 [Components] 對話窗中,選擇你需要額外安裝的 iOS Simulator

Xamarin.Forms 如何在資料繫結中,使用數值轉換器將來源資料經過轉換傳到目標

數值轉換器 (Value COnverter) 在開發以 XAML 為基礎的專案,並且在進行資料繫結的時候,是相當重要的一個應用,在這份筆記中,將會使用數值轉換器,針對所綁定的字串來源,經過數值轉換器之後,就可以轉換成為 Color 物件,並且綁定到目標控制項的屬性上。

如何開發數值轉換器的功能

  1. 建立新類別,使用 IValueConverter 來實作兩個方法
  2. public object Convert(object value, Type targetType, object parameter, CultureInfo culture) 這個方法是最為重要的,通常,也只會實作這個方法。
    在這個方法內,資料繫結功能,會將來源資料傳入到 value 這個參數內,此時,只需要判斷這個物件的值是否為所需要的型別,並且值的內容為何,此時,就可以根據傳入的值,來回傳適當的顏色。
  3. 在頁面內,需要在 ResourceDictionary 內,宣告要產生這個數值轉換器,使用這個方式來宣告。
    <local:ColorTypeToColorConverter x:Key="ColorTypeToColorConverter" />
    如此,在這個頁面之內,若需要使用這個數值轉換器,就可以使用 x:Key 所定義的值,引用這個數值轉換器。
  4. 在 BoxView 的 Color 屬性中,定義其資料繫結,如下所示:
    Color="{Binding ColorType, Converter={StaticResource ColorTypeToColorConverter}}"
    在上方的 XAML 資料繫結宣告中,會將 Color 這個屬性與 ViewModel 內的 ColorType 的屬性綁定在一起,這個 ColorType 屬性為 string 類型,但是,經過了 Convert 轉換之後,就會回傳 Color 的物件。
IValueConverter

ColorTypeToColorConverter.cs

using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xamarin.Forms;

namespace XFIValueConverter
{
    class ColorTypeToColorConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            var foo = value as string;
            if (foo == "1")
            {
                return Color.Red;
            }
            else if (foo == "2")
            {
                return Color.Blue;
            }
            else if (foo == "3")
            {
                return Color.Green;
            }
            else
            {
                return Color.Black;
            }
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }
}

MainPage.xaml

<?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:XFIValueConverter"
             prism:ViewModelLocator.AutowireViewModel="True"
             x:Class="XFIValueConverter.Views.MainPage"
             Title="MainPage">

    <ContentPage.Resources>
        <ResourceDictionary>
            <local:ColorTypeToColorConverter x:Key="ColorTypeToColorConverter" />
        </ResourceDictionary>
    </ContentPage.Resources>

    <StackLayout HorizontalOptions="Center" VerticalOptions="Center">
        <Label Text="輸入數值,可以變換顏色" />
        <Entry Text="{Binding ColorType, Mode=TwoWay}" />
        <BoxView Color="{Binding ColorType, Converter={StaticResource ColorTypeToColorConverter}}"
             WidthRequest="150" HeightRequest="150" />
    </StackLayout>
</ContentPage>

MainPageViewModel.cs

using Prism.Commands;
using Prism.Mvvm;
using Prism.Navigation;
using System;
using System.Collections.Generic;
using System.Linq;

namespace XFIValueConverter.ViewModels
{
    public class MainPageViewModel : BindableBase, INavigationAware
    {
        private string _title;
        public string Title
        {
            get { return _title; }
            set { SetProperty(ref _title, value); }
        }

        #region ColorType
        private string colorType;
        /// <summary>
        /// ColorType
        /// </summary>
        public string ColorType
        {
            get { return this.colorType; }
            set { this.SetProperty(ref this.colorType, value); }
        }
        #endregion

        public MainPageViewModel()
        {

        }

        public void OnNavigatedFrom(NavigationParameters parameters)
        {

        }

        public void OnNavigatedTo(NavigationParameters parameters)
        {
            if (parameters.ContainsKey("title"))
                Title = (string)parameters["title"] + " and Prism";
        }
    }
}

2016/11/01

更新到 Xcode 8.1 之 Visual Studio 開發 Xamarin.Forms 注意事項

  • 這份文件是於 2016/11/01 撰寫,描述一般當 Mac 電腦上的 Xcode 要更新的時候,Windows & Mac 電腦上,也需要進行更新內容的步驟。
  • 請將 Windows 下的 Visual Studio 2015 內的 Xamarin Toolkit 更新到最新版本
    Xamarin 4.2.0.719
    Xamarin.Android 7.0.1.6
    Xamarin.iOS 10.2.0.4
  • 請更新 iOS Simulator for Windows 更新到 10/28 的最新版本
  • 請更新 Mac 電腦上的 Xcode 到 8.1 版本,於更新完成後,請記得要開啟 Xcode,此時,會出現底下對話窗,請點選 Install
    Install additional required components?
    Xcode requires additional components to support running and debugging. Choose install to add required components.
    XcodeInstallRequire
    XcodeInstallComponents
    更新後的 Xcode 版本為 8.1 (8B62)
    Xcode81
  • 接著,請更新 Mac 電腦上的 Xamarin Studio 到最新版本
    Xamarin Studio 6.1.1 (Build 17)
    Xamarin.Android 7.0.1.3
    Xamarin.iOS 10.2.0.4
  • 開啟 VS2015,建立一個新的 Prism 專案
    當要進行 Xamarin Mac Agent 連線的時候,請記得先將 Visual Studio 輸出視窗切換為 Xamarin,再進行 Xamarin Mac Agent的連線登入;當在進行連線的時候,您會在輸出視窗中,看到有更新的動作,此時,要稍等一下,就會完成與 Mac 電腦的連線。
    VS2015的輸出
    在 iOS 專案上,使用滑鼠右鍵,選擇 建置,建置這個 iOS 專案,若沒有發現錯誤,此時,就可以切換為 iOS Simulator,接著在模擬器上執行看看。
    當 iOS Simulator 開始執行的時候,也會有更新
    iOSSimulator更新
  • 建置 iOS 專案的結果
1>------ 已開始全部重建: 專案: PrismUnityApp9, 組態: Debug Any CPU ------
1>  PrismUnityApp9 -> C:\Vulcan\GitBook\Temp\PrismUnityApp9\PrismUnityApp9\PrismUnityApp9\bin\Debug\PrismUnityApp9.dll
2>------ 已開始全部重建: 專案: PrismUnityApp9.iOS, 組態: Debug iPhoneSimulator ------
2>  Generated session id: a8b64c786fe72fb61874d0cabb16ad64
2>  Generated build app name: PrismUnityApp9.iOS
2>  Connecting to Mac server 192.168.1.110...
2>  PrismUnityApp9.iOS -> C:\Vulcan\GitBook\Temp\PrismUnityApp9\PrismUnityApp9\PrismUnityApp9.iOS\bin\iPhoneSimulator\Debug\PrismUnityApp9.iOS.exe
2>  Detected signing identity:
2>    Bundle Id: com.yourcompany.PrismUnityApp9
2>    App Id: com.yourcompany.PrismUnityApp9
========== 全部重建: 2 成功、0 失敗、 0 略過 ==========