XAML in Xamarin.Forms 基礎篇 電子書

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

Xamarin.Forms 快速入門 電子書

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

2018/08/10

在 Xamarin.Forms 使用 SkiaSharp 來進行 2D 圖形繪製 2 : 使用 MVVM 設計方式,在 ViewModel 內來呼叫 SkiaSharp API

根據微軟官方文件 SkiaSharp 簡介 上的說明,SkiaSharp 提供豐富且功能強大 2D 圖形 API,可用來呈現到 2D 的緩衝區。 您可以使用這些來實作自訂使用者介面項目和可整合到您的應用程式的 2D 圖形。 SkiaSharp 是.NET 繫結至Skia程式庫會繼承此文件庫的強大的功能。這也就是說,您可以建立一個 SKCanvasView 控制項,我們便擁有了一個畫布,使用 SkiaSharp 所提供的相關 API,即可以開發出繪製出各種效果的圖片。
在這篇文章中,我們將會 使用 MVVM 設計方式,在 ViewModel 內來呼叫 SkiaSharp API,而在前一篇文章中,我們都是在頁面的 Code Behind 內撰寫呼叫 SkiaSharp 程式碼。
在這個練習專案頁面中,我們設計了兩個 200x200 的 SKCanvasView 控制項,並且使用了 Prism 所提供的 行為 Behavior 功能中的 EventToCommandBehavior,讓我們指定了這些 SKCanvasView 控制項內的指定事件 PaintSurface 若被觸發的話,將會自動去執行 ViewModel 內的 PaintSurfaceCommand 命令。
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:skia="clr-namespace:SkiaSharp.Views.Forms;assembly=SkiaSharp.Views.Forms"
             xmlns:behavior="clr-namespace:Prism.Behaviors;assembly=Prism.Forms"
             xmlns:local="clr-namespace:XFSkiaMVVM"
             x:Class="XFSkiaMVVM.Views.MainPage"
             Title="{Binding Title}">

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

    <ScrollView
        >
        <StackLayout HorizontalOptions="CenterAndExpand" VerticalOptions="CenterAndExpand">
            <BoxView
                Color="Black"
                WidthRequest="200" HeightRequest="200"/>
            <skia:SKCanvasView
                BackgroundColor="Black"
                IgnorePixelScaling="True" 
                WidthRequest="200" HeightRequest="200"
                >
                <skia:SKCanvasView.Behaviors>
                    <behavior:EventToCommandBehavior
                        EventName="PaintSurface"
                        Command="{Binding PaintSurfaceCommand}"
                        EventArgsConverter="{StaticResource SKPaintSurfaceEventArgsConverter}"
                    />
                </skia:SKCanvasView.Behaviors>
            </skia:SKCanvasView>
            <skia:SKCanvasView
                BackgroundColor="Black"
                IgnorePixelScaling="False" 
                WidthRequest="200" HeightRequest="200"
                >
                <skia:SKCanvasView.Behaviors>
                    <behavior:EventToCommandBehavior
                        EventName="PaintSurface"
                        Command="{Binding PaintSurfaceSelfScaleCommand}"
                        EventArgsConverter="{StaticResource SKPaintSurfaceEventArgsConverter}"
                        />
                </skia:SKCanvasView.Behaviors>
            </skia:SKCanvasView>
        </StackLayout>
    </ScrollView>

</ContentPage>
不過,在這裡,您也看到 EventArgsConverter="{StaticResource SKPaintSurfaceEventArgsConverter}" 這個 XAML 敘述,底下將會是這個 數值轉換器 Value Converter 之 SKPaintSurfaceEventArgsConverter 定義程式碼。由於我們需要在 ViewModel 內取得該事件傳入進來的參數,因此,我們建立一個數值轉換器,並且使用 EventArgsConverter 來指定要將事件傳入進來的參數,可以我們在 ViewModel 內來使用。我們可以看到,我們會透過數值轉換器傳入進來的 value 參數值,轉型成為該事件的參數型別,也就是,SKPaintSurfaceEventArgs,並且將這個值回傳回去。
C#
using SkiaSharp.Views.Forms;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Text;
using Xamarin.Forms;

namespace XFSkiaMVVM
{
    class SKPaintSurfaceEventArgsConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            var skPaintSurfaceEventArgs = value as SKPaintSurfaceEventArgs;
            if (skPaintSurfaceEventArgs == null)
            {
                throw new ArgumentException("Expected value to be of type SKPaintSurfaceEventArgs", nameof(value));
            }
            return skPaintSurfaceEventArgs;
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }
}
那麼,究竟要如何在 ViewModel 內讀取該事件傳入進來的參數值呢?在這裡,當我們要宣告事件2命令的命令時候,要使用泛型的方式來宣告其型別,也就是類似這樣 public DelegateCommand<SKPaintSurfaceEventArgs> PaintSurfaceCommand { get; set; } 在這裡,我們就看到了剛剛的數值轉換器的轉型型別,也就是我們命令中的要指定的泛型型別。接下來,在我們建立這個命令的物件時候,就可以使用 PaintSurfaceCommand = new DelegateCommand<SKPaintSurfaceEventArgs>(args => { ... } 這樣敘述來建立,我們使用了 Lambda 匿名函式傳入到這個命令建構式內,而我們在這個匿名函式內,就可以透過 args 這個參數變數,取得原先在 SKCanvasView 控制項 PaintSurface 事件內的事件參數物件。有了 SKPaintSurfaceEventArgs 這個參數物件,我們便可以開始進行針對 SKCanvasView 畫布,呼叫各種 SkiaSharp API,進行繪圖需求工作了。
若您仔細觀察執行結果,您將會發現到第一個 SKCanvasView 控制項所繪製出來的圓形與線條會有鋸齒狀,而且,這裡所指定畫線與畫圓的 API 使用到的尺寸都是 與裝置無關的畫素,也就是沒有根據當時螢幕的縮放比來自行計算出真實畫素實際值,這是因為,我們在 SKCanvasView 控制項內,設定了 IgnorePixelScaling="True" 屬性值,當 IgnorePixelScaling 屬性值為真,我們在 SKCanvasView 控制項內的所指定的尺寸,就可以使用 XAML 中設定的尺寸大小, SkiaSharp 會自動幫我們進行縮放,可是,您看到這樣的效果並不是很好,因為,會有鋸齒狀出現。
所以,我們還是建議類似 PaintSurfaceSelfScaleCommand 命令中的做法,使用 float fooScale = info.Width / 200.0f; canvas.Scale(fooScale); 敘述,呼叫 Scale 方法,指定縮放比率值,這樣就不會有鋸齒狀出現了。
C#
using Prism.Commands;
using Prism.Mvvm;
using Prism.Navigation;
using SkiaSharp;
using SkiaSharp.Views.Forms;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;

namespace XFSkiaMVVM.ViewModels
{

    public class MainPageViewModel : INotifyPropertyChanged, INavigationAware
    {
        public event PropertyChangedEventHandler PropertyChanged;
        public DelegateCommand<SKPaintSurfaceEventArgs> PaintSurfaceCommand { get; set; }
        public DelegateCommand<SKPaintSurfaceEventArgs> PaintSurfaceSelfScaleCommand { get; set; }
        private readonly INavigationService _navigationService;

        public MainPageViewModel(INavigationService navigationService)
        {
            _navigationService = navigationService;

            PaintSurfaceCommand = new DelegateCommand<SKPaintSurfaceEventArgs>(args =>
           {
               SKImageInfo info = args.Info;
               SKSurface surface = args.Surface;
               SKCanvas canvas = surface.Canvas;

               canvas.Clear();

               SKPaint fooCirclePaint = new SKPaint
               {
                   Style = SKPaintStyle.Fill,
                   Color = SKColors.DeepSkyBlue,
                   StrokeWidth=1,
               };

               SKPaint fooLinePaint = new SKPaint
               {
                   Style = SKPaintStyle.Stroke,
                   Color = SKColors.White,
                   StrokeWidth = 1,
               };

               canvas.DrawCircle(100, 100, 100, fooCirclePaint);
               canvas.DrawLine(0, 0, 200, 140, fooLinePaint);
           });

            PaintSurfaceSelfScaleCommand = new DelegateCommand<SKPaintSurfaceEventArgs>(args =>
           {
               SKImageInfo info = args.Info;
               SKSurface surface = args.Surface;
               SKCanvas canvas = surface.Canvas;

               canvas.Clear();

               float fooScale = info.Width / 200.0f;

               SKPaint fooCirclePaint = new SKPaint
               {
                   Style = SKPaintStyle.Fill,
                   Color = SKColors.DeepSkyBlue,
                   StrokeWidth = 1,
               };

               SKPaint fooLinePaint = new SKPaint
               {
                   Style = SKPaintStyle.Stroke,
                   Color = SKColors.White,
                   StrokeWidth = 1,
               };

               canvas.Scale(fooScale);
               canvas.DrawCircle(100, 100, 100, fooCirclePaint);
               canvas.DrawLine(0, 0, 200, 140, fooLinePaint);
           });

        }

        public void OnNavigatedFrom(NavigationParameters parameters)
        {

        }

        public void OnNavigatingTo(NavigationParameters parameters)
        {

        }

        public void OnNavigatedTo(NavigationParameters parameters)
        {

        }

    }
}
  • Android 平台執行結果
    SkiaSharp
  • UWP 平台執行結果
    SkiaSharp

關於 Xamarin 在台灣的學習技術資源

Xamarin 實驗室 粉絲團
歡迎加入 Xamarin 實驗室 粉絲團,在這裡,將會經常性的貼出各種關於 Xamarin / Visual Studio / .NET 的相關消息、文章、技術開發等文件,讓您可以隨時掌握第一手的 Xamarin 方面消息。
Xamarin.Forms @ Taiwan
歡迎加入 Xamarin.Forms @ Taiwan,這是台灣的 Xamarin User Group,若您有任何關於 Xamarin / Visual Studio / .NET 上的問題,都可以在這裡來與各方高手來進行討論、交流。
Xamarin 實驗室 部落格
Xamarin 實驗室 部落格 是作者本身的部落格,這個部落格將會專注於 Xamarin 之跨平台 (Android / iOS / UWP) 方面的各類開技術探討、研究與分享的文章,最重要的是,它是全繁體中文。
Xamarin.Forms 系列課程
Xamarin.Forms 系列課程 想要快速進入到 Xamarin.Forms 的開發領域,學會各種 Xamarin.Forms 跨平台開發技術,例如:MVVM、Prism、Data Binding、各種 頁面 Page / 版面配置 Layout / 控制項 Control 的用法等等,千萬不要錯過這些 Xamarin.Forms 課程




2018/08/09

在 Xamarin.Forms 使用 SkiaSharp 來進行 2D 圖形繪製 1

根據微軟官方文件 SkiaSharp 簡介 上的說明,SkiaSharp 提供豐富且功能強大 2D 圖形 API,可用來呈現到 2D 的緩衝區。 您可以使用這些來實作自訂使用者介面項目和可整合到您的應用程式的 2D 圖形。 SkiaSharp 是.NET 繫結至Skia程式庫會繼承此文件庫的強大的功能。這也就是說,您可以建立一個 SKCanvasView 控制項,我們便擁有了一個畫布,使用 SkiaSharp 所提供的相關 API,即可以開發出繪製出各種效果的圖片。
想要能夠使用 SkiaSharp API 各項功能,首先,您需要知道在 SkiaSharp 裡面的座標系統與尺寸單位定義;左上角是這個畫布的原點,越往右邊, X 軸的值越大,越往下面,Y 軸的值越大;另外,在 SKCanvasView 控制項內,若要執行任何繪製圖形的 API,其標示尺寸單位畫素 Pixel。
在我們這個練習範例中,我們在 XAML 中,建立了三個 SKCanvasView 控制項,其指定的寬度與高度分別為 80x200,在 XAML 中所指定的高度與寬度的單位為 與裝置無關的畫素,也就是會依據您當時執行的裝置之螢幕縮放比與當時裝置螢幕的解析度,經過換算之後,所得到的值,在我們針對 Android 專案執行的時候,當時使用的 Android 模擬器的縮放比為 2.65,那麼,也就是說,這個 SKCanvasView 控制項內可以使用的畫素為 80 x 2.65 (W) / 200 x 2.65 (H) = 212 (W) / 530 (H),若您呼叫 SkiaSharp API 進行繪圖的時候,超過這個寬度與高度,您所繪製的圖形將不會顯示在螢幕上。
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:skia="clr-namespace:SkiaSharp.Views.Forms;assembly=SkiaSharp.Views.Forms"
             x:Class="XFSkiaSharp.Views.MainPage"
             Title="SkiaSharp 練習">

    <StackLayout
        Orientation="Vertical"
        >
        <Label
            x:Name="label1"/>
        <Label
            x:Name="label2"/>
        <Label
            x:Name="label3"/>
        <StackLayout 
            Orientation="Horizontal"
            HorizontalOptions="CenterAndExpand" VerticalOptions="CenterAndExpand">

            <BoxView
                x:Name="boxview"
                Color="LightBlue"
                WidthRequest="80" HeightRequest="200"/>

            <skia:SKCanvasView
                x:Name="canvasView"
                WidthRequest="80" HeightRequest="200"
                PaintSurface="OnCanvasViewPaintSurface"/>

            <skia:SKCanvasView
                WidthRequest="80" HeightRequest="200"
                PaintSurface="OnCanvasViewPaintSurfaceScale"/>

            <skia:SKCanvasView
                WidthRequest="80" HeightRequest="200"
                PaintSurface="OnCanvasViewPaintSurfaceScale2"/>
        </StackLayout>
    </StackLayout>

</ContentPage>
想要取得 SKCanvasView 控制項的有效高度與寬度尺寸畫素,可以在該控制項 SKCanvasView 的 OnCanvasViewPaintSurface 事件內,透過該事件的參數 SKPaintSurfaceEventArgs.Canvas 取得當時畫布的可用畫素 Pixel。
我們在這裡了解幾個 SkiaSharp API 用法,首先是把畫布完全清空,在這裡,我們可以呼叫 SKPaintSurfaceEventArgs.Canvas.Clear() 方法即可。若要指定要繪製圖形的畫筆顏色或者填滿背景顏色等等,可以建立一個 SKPaint 物件,指定相關屬性值即可。在這裡,我們會繪製出一個有顏色填滿的矩形,我們可以使用 SKPaintSurfaceEventArgs.Canvas.DrawRect(0, 0, 80, 200, paint); 這個方法,這裡將會指定要在 SKCanvasView 畫布內,繪製出寬度為 80 畫素,高度為 200 畫素的矩形。由上面所提到的,若在螢幕縮放比為 2.65 的裝置上,執行這 DrawRect API ,所繪製出來的矩形,將不會完全佔據整個 SKCanvasView 控制項,而是一小塊,且位於該畫布左上較區域的一個矩形,會造成這樣的情況,那是因為該畫布可用的畫素為 212 (W) / 530 (H)。這裡所提到的執行結果與相關程式碼,可以參考這個 OnCanvasViewPaintSurface 事件內的程式碼。
不過,這樣可以能對於要進行畫布上進行呼叫 SkiaSharp 繪圖 API 時候,產生一些困擾,這裡可以參考 OnCanvasViewPaintSurfaceScale 這個事件內的程式碼,在這裡,我們使用了這個程式碼,指定繪製出一個矩形 float fooScale = 2.65f; SKPaintSurfaceEventArgs.Canvas.DrawRect(0, 0, 80 * fooScale, 200 * fooScale, paint); ;您可以看到,我們把要繪製的 80W x 200H 的矩形,放大了 2.65 倍率,也就是要指定 SkiaSharp 繪製出 212W x 530H ,這樣,就可以繪製出充滿整個 SKCanvasView 控制項的矩形圖形了。
當然,您會覺得這樣的使用方式還是很不方便,我們每次都需要自行來計算要繪製的座標點與尺寸的縮放倍率,此時,您可以參考 OnCanvasViewPaintSurfaceScale2 事件內的用法,在這裡,我們完全都使用 與裝置無關的畫素 作為標示尺寸的單位,在這裡,我們只要在呼叫任何 SkiaSharp API 之前,先執行這樣的程式碼 SKPaintSurfaceEventArgs.Canvas.Scale(2.65f); 這樣,我們一樣呼叫 SKPaintSurfaceEventArgs.Canvas.DrawRect(0, 0, 80, 200, paint); API,這樣所繪製出來的矩形,也是充滿整個畫布的。
C#
using SkiaSharp;
using SkiaSharp.Views.Forms;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xamarin.Forms;

namespace XFSkiaSharp.Views
{
    public partial class MainPage : ContentPage
    {
        public MainPage()
        {
            InitializeComponent();
        }
        void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs args)
        {
            SKImageInfo info = args.Info;
            SKSurface surface = args.Surface;
            SKCanvas canvas = surface.Canvas;

            canvas.Clear();

            SKPaint paint = new SKPaint
            {
                Style = SKPaintStyle.Fill,
                Color = SKColors.LightBlue,
                StrokeWidth = 1,

            };
            canvas.DrawRect(0, 0, 80, 200, paint);

            label1.Text = $"SKCanvasView Independent Pixel= {canvasView.Width} x {canvasView.Height} ";
            label2.Text = $"SKCanvasView Pixel= {canvasView.CanvasSize.Width} x {canvasView.CanvasSize.Height} ";
            label3.Text = $"SKCanvasView Scale = {canvasView.CanvasSize.Width / canvasView.Width} x {canvasView.CanvasSize.Height / canvasView.Height} ";
        }
        void OnCanvasViewPaintSurfaceScale(object sender, SKPaintSurfaceEventArgs args)
        {
            SKImageInfo info = args.Info;
            SKSurface surface = args.Surface;
            SKCanvas canvas = surface.Canvas;

            canvas.Clear();

            float fooScale = 2.65f;
            SKPaint paint = new SKPaint
            {
                Style = SKPaintStyle.Fill,
                Color = SKColors.LightBlue,
                StrokeWidth = 1,

            };
            canvas.DrawRect(0, 0, 80 * fooScale, 200 * fooScale, paint);
        }
        void OnCanvasViewPaintSurfaceScale2(object sender, SKPaintSurfaceEventArgs args)
        {
            SKImageInfo info = args.Info;
            SKSurface surface = args.Surface;
            SKCanvas canvas = surface.Canvas;

            canvas.Clear();

            SKPaint paint = new SKPaint
            {
                Style = SKPaintStyle.Fill,
                Color = SKColors.LightBlue,
                StrokeWidth = 1,

            };
            canvas.Scale(2.65f);
            canvas.DrawRect(0, 0, 80, 200, paint);
        }
    }
}
  • Android 平台執行結果
    SkiaSharp
  • UWP 平台執行結果
    SkiaSharp

關於 Xamarin 在台灣的學習技術資源

Xamarin 實驗室 粉絲團
歡迎加入 Xamarin 實驗室 粉絲團,在這裡,將會經常性的貼出各種關於 Xamarin / Visual Studio / .NET 的相關消息、文章、技術開發等文件,讓您可以隨時掌握第一手的 Xamarin 方面消息。
Xamarin.Forms @ Taiwan
歡迎加入 Xamarin.Forms @ Taiwan,這是台灣的 Xamarin User Group,若您有任何關於 Xamarin / Visual Studio / .NET 上的問題,都可以在這裡來與各方高手來進行討論、交流。
Xamarin 實驗室 部落格
Xamarin 實驗室 部落格 是作者本身的部落格,這個部落格將會專注於 Xamarin 之跨平台 (Android / iOS / UWP) 方面的各類開技術探討、研究與分享的文章,最重要的是,它是全繁體中文。
+

Xamarin.Forms 系列課程
Xamarin.Forms 系列課程 想要快速進入到 Xamarin.Forms 的開發領域,學會各種 Xamarin.Forms 跨平台開發技術,例如:MVVM、Prism、Data Binding、各種 頁面 Page / 版面配置 Layout / 控制項 Control 的用法等等,千萬不要錯過這些 Xamarin.Forms 課程



開啟某些舊的 Xamarin.Forms 要進行執行,發生這些錯誤訊息 : No resource found that matches the given name

在五月左右進行 Xamarin.Forms 課程教學的時候,經常會發生這樣的問題,不過,那個時候比較忙,沒有時間進行將這個問題整理出來,今天正好要來撰寫 SkiaSharp 的使用文章,因此,打開了之前寫好的範例專案,接著進行 Android 專案的建置,此時,出現了下圖錯誤:
No resource found that matches the given name
上圖的錯誤訊息文字如下所示
錯誤        No resource found that matches the given name: attr 'windowNoTitle'.    XFSkiaSharp.Android    D:\Vulcan\GitHub\xamarin-forms-sample2018\XFSkiaSharp\XFSkiaSharp\XFSkiaSharp.Android\Resources\values\styles.xml    2    
錯誤        No resource found that matches the given name: attr 'windowActionModeOverlay'.    XFSkiaSharp.Android    D:\Vulcan\GitHub\xamarin-forms-sample2018\XFSkiaSharp\XFSkiaSharp\XFSkiaSharp.Android\Resources\values\styles.xml    4    
錯誤        No resource found that matches the given name: attr 'windowActionBar'.    XFSkiaSharp.Android    D:\Vulcan\GitHub\xamarin-forms-sample2018\XFSkiaSharp\XFSkiaSharp\XFSkiaSharp.Android\Resources\values\styles.xml    2    
錯誤        No resource found that matches the given name: attr 'colorPrimaryDark'.    XFSkiaSharp.Android    D:\Vulcan\GitHub\xamarin-forms-sample2018\XFSkiaSharp\XFSkiaSharp\XFSkiaSharp.Android\Resources\values\styles.xml    2    
錯誤        No resource found that matches the given name: attr 'colorPrimary'.    XFSkiaSharp.Android    D:\Vulcan\GitHub\xamarin-forms-sample2018\XFSkiaSharp\XFSkiaSharp\XFSkiaSharp.Android\Resources\values\styles.xml    2    
錯誤        No resource found that matches the given name: attr 'colorAccent'.    XFSkiaSharp.Android    D:\Vulcan\GitHub\xamarin-forms-sample2018\XFSkiaSharp\XFSkiaSharp\XFSkiaSharp.Android\Resources\values\styles.xml    3    
錯誤        No resource found that matches the given name: attr 'colorAccent'.    XFSkiaSharp.Android    D:\Vulcan\GitHub\xamarin-forms-sample2018\XFSkiaSharp\XFSkiaSharp\XFSkiaSharp.Android\Resources\values\styles.xml    4    
錯誤        Error retrieving parent for item: No resource found that matches the given name 'Theme.AppCompat.Light.Dialog'.    XFSkiaSharp.Android    D:\Vulcan\GitHub\xamarin-forms-sample2018\XFSkiaSharp\XFSkiaSharp\XFSkiaSharp.Android\Resources\values\styles.xml    4    
錯誤        Error retrieving parent for item: No resource found that matches the given name 'Theme.AppCompat.Light.DarkActionBar'.    XFSkiaSharp.Android    D:\Vulcan\GitHub\xamarin-forms-sample2018\XFSkiaSharp\XFSkiaSharp\XFSkiaSharp.Android\Resources\values\styles.xml    2
大部分的人遇到這樣的錯誤訊息的時候,大多會束手無策,而且似乎找不到好的方法可以解決這個問題,在這裡,可以根據我的作法,施展大絕招來解決此一問題
  • 請先使用滑鼠右擊方案節點,選擇 清除方案 選項
    Clean Visual Studio Solution
  • 清除完成後,可以建置 Android 專案,您會發現會得到一樣的錯誤訊息
  • 現在,請關閉 Visual Studio 2017 程式
  • 重新開啟 Visual Studio 2017,並且打開這個相同專案
  • 請重新建置這個 Android 專案
  • 您將會發現到您已經可以成功建立這個 Android 專案了,在輸出視窗內,將會看到底下的訊息
    1>------ 已開始全部重建: 專案: XFSkiaSharp, 組態: Debug Any CPU ------
    1>XFSkiaSharp -> D:\Vulcan\GitHub\xamarin-forms-sample2018\XFSkiaSharp\XFSkiaSharp\XFSkiaSharp\bin\Debug\netstandard2.0\XFSkiaSharp.dll
    2>------ 已開始全部重建: 專案: XFSkiaSharp.Android, 組態: Debug Any CPU ------
    2>  XFSkiaSharp.Android -> D:\Vulcan\GitHub\xamarin-forms-sample2018\XFSkiaSharp\XFSkiaSharp\XFSkiaSharp.Android\bin\Debug\XFSkiaSharp.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 略過 ==========
    

關於 Xamarin 在台灣的學習技術資源

Xamarin 實驗室 粉絲團
歡迎加入 Xamarin 實驗室 粉絲團,在這裡,將會經常性的貼出各種關於 Xamarin / Visual Studio / .NET 的相關消息、文章、技術開發等文件,讓您可以隨時掌握第一手的 Xamarin 方面消息。
Xamarin.Forms @ Taiwan
歡迎加入 Xamarin.Forms @ Taiwan,這是台灣的 Xamarin User Group,若您有任何關於 Xamarin / Visual Studio / .NET 上的問題,都可以在這裡來與各方高手來進行討論、交流。
Xamarin 實驗室 部落格
Xamarin 實驗室 部落格 是作者本身的部落格,這個部落格將會專注於 Xamarin 之跨平台 (Android / iOS / UWP) 方面的各類開技術探討、研究與分享的文章,最重要的是,它是全繁體中文。
Xamarin.Forms 系列課程
Xamarin.Forms 系列課程 想要快速進入到 Xamarin.Forms 的開發領域,學會各種 Xamarin.Forms 跨平台開發技術,例如:MVVM、Prism、Data Binding、各種 頁面 Page / 版面配置 Layout / 控制項 Control 的用法等等,千萬不要錯過這些 Xamarin.Forms 課程