XAML in Xamarin.Forms 基礎篇 電子書

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

Xamarin.Forms 快速入門 電子書

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

2018/05/23

Xamarn.Forms TabbedPage 標籤式頁面的不同情境之使用

在從事 Xamarin.Forms 教學經驗中,有許多人都在詢問要如何設計出具有 TabbedPage 標籤式頁面 功能,不過,因為我個人比較少使用這個頁面,通常遇到這樣的視覺需求,我都是自行設計使用者控制向來完成這樣的需求,因此,在這篇文章中,我們將要來體驗 TabbedPage 標籤式頁面在 Xamarin.Forms 中要如何使用?不過,我們在這裡所練習的架構,是採用 Prism 框架下的 MVVM 設計模式,並且需要使用到 Prism7 的版本才能夠時做出來。
這篇文章所提到的所有專案原始碼,可以從 這裡 取得
在我們的練習情境之中,我們需要設計一個應用程式的首頁為 TabbedPage 標籤式頁面,在這個 TabbedPage 標籤式頁面中,共會存在四個標籤 (在 Prism7 中,我們可以使用這個查詢字串 createTab 來完成宣告,這個標籤頁面總共需要有多少個頁面存在),不過,我們需要指定第三個標籤頁面為我們預設顯示的頁面,底下為我們實際執行後的螢幕截圖,預設顯示第三頁面內容 (在 Prism7 中,我們可以使用這個查詢字串 selectedTab 來指定預設顯示的頁次是哪個)。
TabbedPage 標籤式頁面
另外,我們希望切換到第二個標籤頁面的時候,他是具有導航工具列的效果,也就是說,我們切換到第二頁的時候,在第二頁內會有一個按鈕,按下這個按鈕之後,將會導航到另外一個新的頁面,在此同時,螢幕上會有導航工具列出現,如同下圖:
TabbedPage 標籤式頁面 TabbedPage 標籤式頁面
不過,若我們沒有使用 Prism7 所提供的標籤頁面之特定查詢字串,此時,我們將會變成這樣的情境,這樣的結果將不是我們所期望需要的。
TabbedPage 標籤式頁面 TabbedPage 標籤式頁面
接下來,我們來實際練習開發出這樣的應用。

建立練習專案

  • 首先,我們使用 Prism Template Pack (現在使用的 2.0.9 版本)建立起一個 Xamarin.Forms 開發專案
  • 我們需要建立一個 TabbedPage 頁面,我們把它命名為 MainTabbedPage,在這個頁面 View 與頁面檢視 ViewModel 中,我們不需要做任何特別處理。
  • 另外,因為我們需要有許多標籤頁次需要顯示,因此,我們需要建立出五個 ContentPage,所以,我們產生出五個 ContentPage,分別名稱為 Page1, Page2, Page3, Page4, Page21。 Visual Studio 2017 Solution Explorer
  • 接下來,我們需要分別將這五個 ContentPage 的 View 和 ViewModel 進行設計
  • 最後,我們需要修正 Xamarin.Forms 專案的進入點 ( Entry Point ),也就是 App.xaml.cs 檔案,我們將其打開,在 OnInitialized 方法內,將 await NavigationService.NavigateAsync 方法內需要的引數,修改成為 MainTabbedPage?createTab=Page1&createTab=NavigationPage|Page2&createTab=Page3&createTab=Page4&selectedTab=Page3
    在這裡,我們透過了查詢字串中 createTab 這個參數,指定這個標籤式頁面需要那些 ContentPage,由於我們在這個練習中,總共需要用到四個標籤頁面,所以,我們在查詢字串中,總共需要使用到四次的 createTab 。其中,您將會看到在第二個 createTab 中,其設定值似乎與其他的不太一樣,在這裡,我們需要在頁面2中,提供導航到其他頁面的機制,因此,我們需要在 createTab 參數名稱之後,先使用 NavigationPage 緊接著使用管道 | 字元,最後再加上 Page2,這表示了,第二個標籤頁面中,將會顯示出具有導航工具列的效果。
    TabbedPage 標籤式頁面
    而在頁面2中,我們放置了一個按鈕,當您按下這個按鈕之後,將會導航到 Page21 這個頁面,底下是我們所期望呈現的結果。我們可以看到,最上方會出現導航工具列,並且會有回上頁的按鈕出現,不過,新的頁面還是出現在 TabbedPage 標籤式頁面的第二個頁次中。
    TabbedPage 標籤式頁面
    若您的專案需要不想要做到這樣的結果,您可以參考頁面1的設計,在這個頁面中,我們放置了一個按鈕,按下這個按鈕,就一樣會導航到 Page21,不過,當您切換到 頁面1 頁次的時候,看到的是如下螢幕截圖,他與頁面2 的內容完全不一樣,您知道為什麼會有這樣的結果嗎?
    TabbedPage 標籤式頁面
    當我們在頁面1點選了這個按鈕,此時,將會出現如下圖內容。
    TabbedPage 標籤式頁面

MainTabbedPage 的 View 內容

<?xml version="1.0" encoding="utf-8" ?>
<TabbedPage 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="XFTabbed2.Views.MainTabbedPage">

</TabbedPage>

Page1 的 View 內容

<?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="XFTabbed2.Views.Page1"
             Title="{Binding Title}"
             BackgroundColor="LightBlue">

    <StackLayout
        >
        <Button
            Text="Go Page21"
            Command="{Binding GoNextCommand}"/>
    </StackLayout>
</ContentPage>

Page1ViewModel 的 ViewModel 程式碼

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

namespace XFTabbed2.ViewModels
{
    using System.ComponentModel;
    using Prism.Events;
    using Prism.Navigation;
    using Prism.Services;
    public class Page1ViewModel : INotifyPropertyChanged, INavigationAware
    {
        public event PropertyChangedEventHandler PropertyChanged;
        public string Title { get; set; }
        private readonly INavigationService _navigationService;
        public DelegateCommand GoNextCommand { get; set; }
        public Page1ViewModel(INavigationService navigationService)
        {
            _navigationService = navigationService;
            Title = "頁面 1";
            GoNextCommand = new DelegateCommand(() =>
            {
                _navigationService.NavigateAsync("Page21");
            });
        }

        public void OnNavigatedFrom(NavigationParameters parameters)
        {

        }

        public void OnNavigatingTo(NavigationParameters parameters)
        {

        }

        public void OnNavigatedTo(NavigationParameters parameters)
        {

        }

    }
}

Page2 的 View 內容

<?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="XFTabbed2.Views.Page2"
             Title="{Binding Title}"
             BackgroundColor="LightGoldenrodYellow">

    <StackLayout
        >
        <Button
            Text="Go Page21"
            Command="{Binding GoNextCommand}"/>
    </StackLayout>

</ContentPage>

Page2ViewModel 的 ViewModel 程式碼

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

namespace XFTabbed2.ViewModels
{
    using System.ComponentModel;
    using Prism.Events;
    using Prism.Navigation;
    using Prism.Services;
    public class Page2ViewModel : INotifyPropertyChanged, INavigationAware
    {
        public event PropertyChangedEventHandler PropertyChanged;
        public string Title { get; set; }
        private readonly INavigationService _navigationService;
        public DelegateCommand GoNextCommand { get; set; }
        public Page2ViewModel(INavigationService navigationService)
        {
            _navigationService = navigationService;
            Title = "頁面 2";
            GoNextCommand = new DelegateCommand(() =>
            {
                _navigationService.NavigateAsync("Page21");
            });
        }

        public void OnNavigatedFrom(NavigationParameters parameters)
        {

        }

        public void OnNavigatingTo(NavigationParameters parameters)
        {

        }

        public void OnNavigatedTo(NavigationParameters parameters)
        {

        }

    }
}

Page21 的 View 內容

<?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="XFTabbed2.Views.Page21"
             Title="{Binding Title}"
             BackgroundColor="LightPink">

</ContentPage>

Page21ViewModel 的 ViewModel 程式碼

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

namespace XFTabbed2.ViewModels
{
    using System.ComponentModel;
    using Prism.Events;
    using Prism.Navigation;
    using Prism.Services;
    public class Page21ViewModel : INotifyPropertyChanged, INavigationAware
    {
        public event PropertyChangedEventHandler PropertyChanged;
        public string Title { get; set; }
        private readonly INavigationService _navigationService;

        public Page21ViewModel(INavigationService navigationService)
        {
            _navigationService = navigationService;
            Title = "頁面 21";
        }

        public void OnNavigatedFrom(NavigationParameters parameters)
        {

        }

        public void OnNavigatingTo(NavigationParameters parameters)
        {

        }

        public void OnNavigatedTo(NavigationParameters parameters)
        {

        }

    }
}

Page3 的 View 內容

<?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="XFTabbed2.Views.Page3"
             Title="{Binding Title}"
             BackgroundColor="LightSalmon">

</ContentPage>

Page3ViewModel 的 ViewModel 程式碼

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

namespace XFTabbed2.ViewModels
{
    using System.ComponentModel;
    using Prism.Events;
    using Prism.Navigation;
    using Prism.Services;
    public class Page3ViewModel : INotifyPropertyChanged, INavigationAware
    {
        public event PropertyChangedEventHandler PropertyChanged;
        public string Title { get; set; }
        private readonly INavigationService _navigationService;

        public Page3ViewModel(INavigationService navigationService)
        {
            _navigationService = navigationService;
            Title = "頁面 3";
        }

        public void OnNavigatedFrom(NavigationParameters parameters)
        {

        }

        public void OnNavigatingTo(NavigationParameters parameters)
        {

        }

        public void OnNavigatedTo(NavigationParameters parameters)
        {

        }

    }
}

Page4 的 View 內容

<?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="XFTabbed2.Views.Page4"
             Title="{Binding Title}"
             BackgroundColor="LightSteelBlue">

</ContentPage>

Page4ViewModel 的 ViewModel 程式碼

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

namespace XFTabbed2.ViewModels
{
    using System.ComponentModel;
    using Prism.Events;
    using Prism.Navigation;
    using Prism.Services;
    public class Page4ViewModel : INotifyPropertyChanged, INavigationAware
    {
        public event PropertyChangedEventHandler PropertyChanged;
        public string Title { get; set; }
        private readonly INavigationService _navigationService;

        public Page4ViewModel(INavigationService navigationService)
        {
            _navigationService = navigationService;
            Title = "頁面 4";
        }

        public void OnNavigatedFrom(NavigationParameters parameters)
        {

        }

        public void OnNavigatingTo(NavigationParameters parameters)
        {

        }

        public void OnNavigatedTo(NavigationParameters parameters)
        {

        }

    }
}



2018/05/22

在 Xamarin-Forms 專案中,第一次體驗 Firebase 資料庫的使用

因為進行 Xamarin 教學課程上的需要,因此,最近特別來研究與體驗如何使用 Firebase 的資料庫功能。
這篇文章的專案原始碼,可以從 這裡 取得
首先,建立起一個 Xamarin.Forms for Prism 專案,讓我們來體驗一下在 C# 中,使用 Firebase 來存取資料庫的應用。
  • 在這個專案中,加入 FirebaseDatabase.net NuGet 套件
  • 接著,我們建立一個資料模型類別,用來宣告要儲存在 Firebase 資料庫內的內容。在這裡,我們宣告一個 MyMoney 類別,用來記錄每筆消費紀錄項目。
public class MyMoney
{
    public Guid Id { get; set; }
    public string Title { get; set; }
    public string InvoiceNo { get; set; }
    public int Cost { get; set; }
}
  • 現在,讓我們開始來使用 Firebase,在這個測試範例程式碼中,我們將會做到:將整個資料表刪除、查詢現在所有的紀錄、刪除指定的紀錄、找出特定的紀錄、修改某筆紀錄、新增10筆紀錄等功能。

View 的內容

底下是我們測試的頁面宣告
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="XFFirebase.Views.MainPage"
             Title="Firebase 資料庫存取測試">

    <Grid
       >
        <Grid.RowDefinitions>
            <RowDefinition Height="*"/>
            <RowDefinition Height="80"/>
        </Grid.RowDefinitions>

        <Editor
            Text="{Binding Output}"/>
        <Button
            Grid.Row="1"
            Text="Start"
            Command="{Binding StartCommand}"/>
    </Grid>

</ContentPage>

ViewModel 的內容

using Prism.Commands;
using Prism.Mvvm;
using Prism.Navigation;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Firebase.Database.Query;


namespace XFFirebase.ViewModels
{
    using System.ComponentModel;
    using Prism.Events;
    using Prism.Navigation;
    using Prism.Services;
    using XFFirebase.Models;

    public class MainPageViewModel : INotifyPropertyChanged, INavigationAware
    {
        public event PropertyChangedEventHandler PropertyChanged;
        public string Output { get; set; }
        public DelegateCommand StartCommand { get; set; }
        private readonly INavigationService _navigationService;

        public MainPageViewModel(INavigationService navigationService)
        {
            _navigationService = navigationService;
            StartCommand = new DelegateCommand(async () =>
            {
                Output = "建立與 Firebase 連線";
                var client = new Firebase.Database.FirebaseClient("https://xamarindb-3408d.firebaseio.com");
                var child = client.Child("MyMoneys");

                Output = Environment.NewLine + Environment.NewLine + "刪除掉所有的資料";
                await child.DeleteAsync();

                Console.WriteLine("產生 10 筆購物紀錄");
                for (int i = 1; i < 10; i++)
                {
                    await child.PostAsync<MyMoney>(new MyMoney()
                    {
                        Id = Guid.NewGuid(),
                        Title = $"冷泡茶 {i} 瓶",
                        InvoiceNo = $"0000 {i}",
                        Cost = 20 * i,
                    });
                }

                Output += Environment.NewLine + Environment.NewLine + "列出 Firebase 中所有的紀錄";
                var fooPosts = await child.OnceAsync<MyMoney>();
                foreach (var item in fooPosts)
                {
                    Output += Environment.NewLine + $"購買商品:{item.Object.Title} 價格:{item.Object.Cost}";
                }

                Output += Environment.NewLine + Environment.NewLine + "查詢購物價格小於 90 的紀錄";
                var fooRec = fooPosts.Where(x => x.Object.Cost <= 90);
                foreach (var item in fooRec)
                {
                    Output += Environment.NewLine + $"購買商品:{item.Object.Title} 價格:{item.Object.Cost}";
                }

                Output += Environment.NewLine + Environment.NewLine + "刪除購物價格小於 90 的紀錄";
                var fooRecDeleted = fooPosts.Where(x => x.Object.Cost <= 90);
                foreach (var item in fooRecDeleted)
                {
                    await child.Child(item.Key).DeleteAsync();
                    Output += Environment.NewLine + $"購買商品:{item.Object.Title} 價格:{item.Object.Cost} 已經被刪除";
                }


                Output += Environment.NewLine + Environment.NewLine + "列出 Firebase 中所有的紀錄";
                fooPosts = await child.OnceAsync<MyMoney>();
                foreach (var item in fooPosts)
                {
                    Output += Environment.NewLine + $"購買商品:{item.Object.Title} 價格:{item.Object.Cost}";
                }

                Output += Environment.NewLine + Environment.NewLine + "查詢購物價格等於 140 的紀錄";
                var foo140Rec = fooPosts.FirstOrDefault(x => x.Object.Cost == 140);
                foo140Rec.Object.Cost = 666;
                await child.Child(foo140Rec.Key).PutAsync(foo140Rec.Object);
                Output += Environment.NewLine + $"購買商品:{foo140Rec.Object.Title} 的價格已經修正為 價格:{foo140Rec.Object.Cost}";

                Output += Environment.NewLine + Environment.NewLine + "列出 Firebase 中所有的紀錄";
                fooPosts = await child.OnceAsync<MyMoney>();
                foreach (var item in fooPosts)
                {
                    Output += Environment.NewLine + $"購買商品:{item.Object.Title} 價格:{item.Object.Cost}";
                }
            });
        }

        public void OnNavigatedFrom(NavigationParameters parameters)
        {

        }

        public void OnNavigatingTo(NavigationParameters parameters)
        {

        }

        public void OnNavigatedTo(NavigationParameters parameters)
        {

        }

    }
}
底下是我們測試頁面的Vidwmodel 相關程式碼

執行結果

Firebase執行結果

2018/05/21

如何解決 Your project is not referencing the "MonoAndroid,Version=v8.1" framework 錯誤說明

了解更多關於 [Xamarin.Android] 的使用方式
了解更多關於 [Xamarin.iOS] 的使用方式
了解更多關於 [Xamarin.Forms] 的使用方式
了解更多關於 [Hello, Android:快速入門] 的使用方式
了解更多關於 [Hello, iOS – 快速入門] 的使用方式
了解更多關於 [Xamarin.Forms 快速入門] 的使用方式

最近將 Surface Pro 4 作業系統重新安裝,並且安裝最新的 Visual Studio 2017 15.7.1 版本,並且透過 Prism Template Pack 來產生一個 Xamarin.Forms 的專案,不過,當想要建置 Android 的專案 (此時,我並沒有進行任何 Xamarin.Forms 的相關設計,只是建立好 Xamarin.Forms 專案),卻得到了底下錯誤訊息。
VS2017 15.7.1 MonoAndroid 8.1 Error
Your project is not referencing the "MonoAndroid,Version=v8.1" framework. 
Add a reference to "MonoAndroid,Version=v8.1" in the "frameworks" section of 
your project.json, and then re-run NuGet restore.
我的另外一台電腦中,在很早之前,就已將安裝了 Visual Studo 2017,不過,這幾天才將 Viusal Studio 2017 從 15.6.x 升級到 15.7.1,不過,我可以確定的是,在我還沒有升級到 VS2017 15.7.1 版本,我是可以順利建立起 Xamarin.Forms 的專案,並且可以順利正常建置該專案。 (有個詭異現象,那就是,這台電腦原本在 15.7.1 版本中,所建立的 Xamarin.Forms 專案,是可以正常建置的,直到昨天晚上,我也沒有做任何升級與安裝相關軟體的動作,卻發生了一樣的問題,卻也會得到一樣的錯誤訊息,無法順利建置成功了)

如何修正這個問題

  • 請在 Visual Studio 2017 的 方案總管中,使用滑鼠雙擊 Android 專案中的 Propertis 節點,找到 應用程式 標籤頁次,並在這個標籤頁次中,您會看到了 使用下列 Android 版本編譯: (目標 Framework) 這個下拉選單,此時他預設的選項是 使用最新平台 (Android 8.1 (Oreo)) Android Properties Application
這個時候,我們先來查看這個 Android 專案的 .csproj 檔案內容,我們看到了,他的 TargetFrameworkVersion 項目標示其值為 v7.1 ,而另外一個標籤 AndroidUseLatestPlatformSdk 該項目的值為 true。
  <PropertyGroup>
    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
    <ProductVersion>8.0.30703</ProductVersion>
    <SchemaVersion>2.0</SchemaVersion>
    <ProjectGuid>{C6CAF76D-0C7C-4DA4-8DE1-617BF0D573C0}</ProjectGuid>
    <ProjectTypeGuids>{EFBA0AD7-5A72-4C68-AF49-83D382785DCF};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
    <OutputType>Library</OutputType>
    <AppDesignerFolder>Properties</AppDesignerFolder>
    <RootNamespace>BlankApp10.Droid</RootNamespace>
    <AssemblyName>BlankApp10.Android</AssemblyName>
    <FileAlignment>512</FileAlignment>
    <TargetFrameworkVersion>v7.1</TargetFrameworkVersion>
    <AndroidApplication>True</AndroidApplication>
    <AndroidResgenFile>Resources\Resource.designer.cs</AndroidResgenFile>
    <GenerateSerializationAssemblies>Off</GenerateSerializationAssemblies>
    <AndroidResgenClass>Resource</AndroidResgenClass>
    <AndroidManifest>Properties\AndroidManifest.xml</AndroidManifest>
    <MonoAndroidResourcePrefix>Resources</MonoAndroidResourcePrefix>
    <MonoAndroidAssetsPrefix>Assets</MonoAndroidAssetsPrefix>
    <AndroidUseLatestPlatformSdk>true</AndroidUseLatestPlatformSdk>
    <AndroidStoreUncompressedFileExtensions />
    <MandroidI18n />
    <JavaMaximumHeapSize />
    <JavaOptions />
    <NuGetPackageImportStamp></NuGetPackageImportStamp>
  </PropertyGroup>
  • 請先選擇 目標 Framework 下拉選單為 Android 8.1 (Oreo),我們也觀察,這個時候,Android .csproj 檔案,變成了如下內容
    注意,我們是將原先的 使用最新平台 (Android 8. Oreo) 選項,變更成為第二個 Android 8.1 (Oreo) 選項
    這個時候,他的 TargetFrameworkVersion 項目標示其值為 8.1 ,而另外一個標籤 AndroidUseLatestPlatformSdk 該項目的值為 false。
    Android Properties Application
  <PropertyGroup>
    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
    <ProductVersion>8.0.30703</ProductVersion>
    <SchemaVersion>2.0</SchemaVersion>
    <ProjectGuid>{C6CAF76D-0C7C-4DA4-8DE1-617BF0D573C0}</ProjectGuid>
    <ProjectTypeGuids>{EFBA0AD7-5A72-4C68-AF49-83D382785DCF};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
    <OutputType>Library</OutputType>
    <AppDesignerFolder>Properties</AppDesignerFolder>
    <RootNamespace>BlankApp10.Droid</RootNamespace>
    <AssemblyName>BlankApp10.Android</AssemblyName>
    <FileAlignment>512</FileAlignment>
    <TargetFrameworkVersion>v8.1</TargetFrameworkVersion>
    <AndroidApplication>True</AndroidApplication>
    <AndroidResgenFile>Resources\Resource.designer.cs</AndroidResgenFile>
    <GenerateSerializationAssemblies>Off</GenerateSerializationAssemblies>
    <AndroidResgenClass>Resource</AndroidResgenClass>
    <AndroidManifest>Properties\AndroidManifest.xml</AndroidManifest>
    <MonoAndroidResourcePrefix>Resources</MonoAndroidResourcePrefix>
    <MonoAndroidAssetsPrefix>Assets</MonoAndroidAssetsPrefix>
    <AndroidUseLatestPlatformSdk>false</AndroidUseLatestPlatformSdk>
    <AndroidStoreUncompressedFileExtensions />
    <MandroidI18n />
    <JavaMaximumHeapSize />
    <JavaOptions />
    <NuGetPackageImportStamp>
    </NuGetPackageImportStamp>
  </PropertyGroup>
  • 最後,請先選擇 目標 Framework 下拉選單為 使用最新平台 (Android 8. Oreo) 選項,我們也觀察,這個時候,Android .csproj 檔案,變成了如下內容
    這個時候,我們再度將目標 Framework 設定選項,修改成為最初產生專案的設定值,即為 使用最新平台
    現在,我們觀察到,專案中的 .csproj 檔案中, TargetFrameworkVersion 項目標示其值為 8.1 ,而另外一個標籤 AndroidUseLatestPlatformSdk 該項目的值為 true。
    Android Properties Application
  <PropertyGroup>
    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
    <ProductVersion>8.0.30703</ProductVersion>
    <SchemaVersion>2.0</SchemaVersion>
    <ProjectGuid>{C6CAF76D-0C7C-4DA4-8DE1-617BF0D573C0}</ProjectGuid>
    <ProjectTypeGuids>{EFBA0AD7-5A72-4C68-AF49-83D382785DCF};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
    <OutputType>Library</OutputType>
    <AppDesignerFolder>Properties</AppDesignerFolder>
    <RootNamespace>BlankApp10.Droid</RootNamespace>
    <AssemblyName>BlankApp10.Android</AssemblyName>
    <FileAlignment>512</FileAlignment>
    <TargetFrameworkVersion>v8.1</TargetFrameworkVersion>
    <AndroidApplication>True</AndroidApplication>
    <AndroidResgenFile>Resources\Resource.designer.cs</AndroidResgenFile>
    <GenerateSerializationAssemblies>Off</GenerateSerializationAssemblies>
    <AndroidResgenClass>Resource</AndroidResgenClass>
    <AndroidManifest>Properties\AndroidManifest.xml</AndroidManifest>
    <MonoAndroidResourcePrefix>Resources</MonoAndroidResourcePrefix>
    <MonoAndroidAssetsPrefix>Assets</MonoAndroidAssetsPrefix>
    <AndroidUseLatestPlatformSdk>true</AndroidUseLatestPlatformSdk>
    <AndroidStoreUncompressedFileExtensions />
    <MandroidI18n />
    <JavaMaximumHeapSize />
    <JavaOptions />
    <NuGetPackageImportStamp>
    </NuGetPackageImportStamp>
  </PropertyGroup>

重新進行建置測試

  • 現在,我們需要重新進行建置動作,為了避免一些雜訊殘留,所以,我們先將這個方案(Solution)進行清除,接著,將 Android 專案與 Xamarin.Forms 專案中的 bin / obj 這兩個目錄,從檔案中刪除掉。
  • 接著,選擇將 Android 專案來建置
  • 稍微等候一段時間,您將會發現到這個 Android 專案,竟然可以順利編譯成功了。
1>------ 已開始建置: 專案: BlankApp10, 組態: Debug Any CPU ------
1>BlankApp10 -> D:\Vulcan\Projects\CannotBuildAndroid\BlankApp10\BlankApp10\BlankApp10\bin\Debug\netstandard2.0\BlankApp10.dll
2>------ 已開始建置: 專案: BlankApp10.Android, 組態: Debug Any CPU ------
2>  BlankApp10.Android -> D:\Vulcan\Projects\CannotBuildAndroid\BlankApp10\BlankApp10\BlankApp10.Android\bin\Debug\BlankApp10.Android.dll
2>  沒有辦法解決 "mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" 和 "mscorlib, Version=2.0.5.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e" 之間的衝突。任意選擇 "mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"。
========== 建置: 2 成功、0 失敗、0 最新、0 略過 ==========
  • 根據從網路上的搜尋與分析,這個問題極有可能是 VS2017 15.7.1 所引發的一個內部 Bug,因此,在尚未取得更新版本的 Visual Studio 2017 前,看樣子,只能夠使用這個方法來進行排除該問題了。