2022年8月12日 星期五

使用 Code Behind 取得裝置畫素與設計尺寸

使用 Code Behind 取得裝置畫素與設計尺寸

對於想要使用 .NET MAUI 來進行跨平台開發的程式設計師,大部分的人最初心選擇將可能是採用 Code Behind 模式,而不是採用 MVVM 的方式,我猜想可能的原因是,絕大部分第一次採用 MAUI 開發的人,對於 MVVM 不太孰悉,有或者是有些懼怕這個新的設計模式的使用,也對於資料綁定 Data Binding 的用法有所懼怕吧。

在這裡將會使用 Code Behind 的方式,透過 .NET MAUI 內建的 平臺整合 內的 裝置顯示資訊 API ,來讀取這些數據。

在這個練習中,其實最重要的是要表達設計尺寸這樣的觀念

建立 .NET MAUI 應用程式 專案

  • 開啟 Visual Studio 2022 Preview 版本

  • 點選螢幕右下角的 [建立新的專案] 按鈕

  • 切換右上角的 [所有專案類型] 下拉選單控制項

  • 找到並且點選 [MAUI] 這個選項

  • 從清單中找到並選擇 [.NET MAUI 應用程式] 這個專案範本

    此專案可用於建立適用於 iOS、Android、Mac Catalyst、Tizen和WinUI 的 .NET MAUI 應用程式

  • 點選右下角的 [下一步] 按鈕

  • 當出現了 [設定新的專案] 對話窗

  • 在 [專案名稱] 欄位內,輸入 MA02

  • 點選右下角的 [下一步] 按鈕

  • 當出現了 [其他資訊] 對話窗

  • 對於 [架構] 的下拉選單控制項,使用預設值

  • 點選右下角的 [建立] 按鈕

修正 View 檢視頁面

  • 在專案根目錄找到並且打開 [MainPage.xaml] 檔案
  • 使用底下 XAML 標記替換這個檔案內容
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="MA02.MainPage"
             Title="裝置螢幕資訊與Code Behind">

    <ScrollView>
        <VerticalStackLayout
            Spacing="25"
            Padding="30,0"
            VerticalOptions="Center">

            <Image
                Source="dotnet_bot.png"
                SemanticProperties.Description="Cute dot net bot waving hi to you!"
                HeightRequest="200"
                HorizontalOptions="Center" />

            <Label
                x:Name="labelDisplay"/>

            <Button
                x:Name="btnGetDisplayInformation"
                Clicked="btnGetDisplayInformation_Clicked"
                Text="取得螢幕畫素資訊"/>

            <Label
                Text="Hello, World!"
                SemanticProperties.HeadingLevel="Level1"
                FontSize="32"
                HorizontalOptions="Center" />

            <Label
                Text="Welcome to .NET Multi-platform App UI"
                SemanticProperties.HeadingLevel="Level2"
                SemanticProperties.Description="Welcome to dot net Multi platform App U I"
                FontSize="18"
                HorizontalOptions="Center" />

            <Button
                x:Name="CounterBtn"
                Text="Click me"
                SemanticProperties.Hint="Counts the number of times you click"
                Clicked="OnCounterClicked"
                HorizontalOptions="Center" />

        </VerticalStackLayout>
    </ScrollView>

</ContentPage>

在這裡,首先在這個根項目 Root Element ,也就是 ContentPage 內容頁面內,加入一個 Title 屬性,在這裡宣告了這個頁面的主題名稱,而這個文字將會顯示在這個頁面最上方。

在這個 版面配置 Layout 的 VerticalStackLayout 裡面,加入兩個檢視,第一個為文字標籤 <Label x:Name="labelDisplay"/>,在這個文字標籤內,使用標記延伸 Markup Extension 語法,也就是 x:Name 宣告這個控制項將會產生一個欄位名稱,也就是 labelDisplay,這個欄位將可以用於這個頁面類別內,讓各種方法或者事件來存取,如此,便可以透過這個物件來變更該文字標籤控制項的各個屬性或者樣貌。

底下將會是 .NET MAUI 根據 MainPage.xaml 這個 XAML 文件檔案內容,採用 原始碼產生器 技術,所產生出來的一個 MainPage 類別。

從這裡首先得知,每個頁面 .xaml 檔案,最終都會形成 .NET 中的一個類別,而在此 XAML 文件中宣告的各個 版面配置、檢視,都會透過這裡的敘述 global::Microsoft.Maui.Controls.Xaml.Extensions.LoadFromXaml(this, typeof(MainPage)); 產生出相對應的 .NET 執行個體,總而言之,這些 xaml 內容,都會有相對應的 .NET 物件存在,每個 XAML 物件,都有相對應的 .NET 類別。

最後,因為在 XAML 文件中有使用到 x:Name="..." 這樣的 XAML 標記延伸 敘述,因此,將會在這個頁面類別內,宣告一個私有欄位 private global::Microsoft.Maui.Controls.Label labelDisplay; ,並且在建構式內,取得這個私有欄位對應的實際 XAML 中宣告的檢視物件 labelDisplay = global::Microsoft.Maui.Controls.NameScopeExtensions.FindByName<global::Microsoft.Maui.Controls.Label>(this, "labelDisplay");

為了要能夠做到與使用者互動機制,因此,加入一個按鈕 Button 按鈕,並且在這個按鈕的 Clicked 屬性中,宣告綁定一個事件 btnGetDisplayInformation_Clicked ,這個事件將會於 Code Behind 區段內進行設計相關商業邏輯程式碼。

[assembly: global::Microsoft.Maui.Controls.Xaml.XamlResourceId("MA02.MainPage.xaml", "MainPage.xaml", typeof(global::MA02.MainPage))]
namespace MA02
{
	[global::Microsoft.Maui.Controls.Xaml.XamlFilePath("MainPage.xaml")]
	public partial class MainPage : global::Microsoft.Maui.Controls.ContentPage
	{
		[global::System.CodeDom.Compiler.GeneratedCode("Microsoft.Maui.Controls.SourceGen", "1.0.0.0")]
		private global::Microsoft.Maui.Controls.Label labelDisplay;

		[global::System.CodeDom.Compiler.GeneratedCode("Microsoft.Maui.Controls.SourceGen", "1.0.0.0")]
		private global::Microsoft.Maui.Controls.Button btnGetDisplayInformation;

        ...

		private void InitializeComponent()
		{
			global::Microsoft.Maui.Controls.Xaml.Extensions.LoadFromXaml(this, typeof(MainPage));
			labelDisplay = global::Microsoft.Maui.Controls.NameScopeExtensions.FindByName<global::Microsoft.Maui.Controls.Label>(this, "labelDisplay");
			btnGetDisplayInformation = global::Microsoft.Maui.Controls.NameScopeExtensions.FindByName<global::Microsoft.Maui.Controls.Button>(this, "btnGetDisplayInformation");
			
            ...
		}
	}
}

修正 View 檢視頁面 Code Behind 程式碼

  • 在專案根目錄找到並且打開 [MainPage.xaml.cs] 檔案
  • 使用底下 C# 程式碼替換這個檔案內容
namespace MA02;

public partial class MainPage : ContentPage
{
    int count = 0;

    public MainPage()
    {
        InitializeComponent();
    }

    private void OnCounterClicked(object sender, EventArgs e)
    {
        count++;

        if (count == 1)
            CounterBtn.Text = $"Clicked {count} time";
        else
            CounterBtn.Text = $"Clicked {count} times";

        SemanticScreenReader.Announce(CounterBtn.Text);
    }

    private void btnGetDisplayInformation_Clicked(object sender, EventArgs e)
    {
        double designWidth =this.Width;
        double designHeight = this.Height;
        IDeviceDisplay display = DeviceDisplay.Current;
        labelDisplay.Text = $"螢幕轉向:{display.MainDisplayInfo.Orientation}{Environment.NewLine}" +
            $"螢幕寬畫素:{display.MainDisplayInfo.Width}{Environment.NewLine}" +
            $"螢幕高畫素:{display.MainDisplayInfo.Height}{Environment.NewLine}" +
            $"設計寬畫素:{designWidth}{Environment.NewLine}" +
            $"設計高畫素:{designHeight}{Environment.NewLine}" +
            $"螢幕密度:{display.MainDisplayInfo.Density}{Environment.NewLine}"+
            $"螢幕更新頻率:{display.MainDisplayInfo.RefreshRate}{Environment.NewLine}";
    }
}

這個類別 MainPage ,設計為一個 partial class 部分類別,那表示了在另外一個地方,也就是原始碼產生器產生的地方,將會產生一個同樣名稱的部分類別,在整個專案編譯過程中,將會把這兩個部分類別程式碼組合成為同一個類別。

在最後面,加入一個 private void btnGetDisplayInformation_Clicked(object sender, EventArgs e) 事件委派方法,在該方法內首先取得這個內容頁面的設計畫素寬度與高度值,接著透過 平台整合 內的 DeviceDisplay.Current 屬性,取得當前這個裝置的螢幕相關資訊,在此將會取得與螢幕有關的相關資訊,例如,這個裝置的真正可用寬度與高度的畫素,現在的密度,也稱之為縮放比率。一旦取得這些資訊之後,便可以將這些字串設定到螢幕上的 文字標籤 檢視的 Text 屬性內,這樣,當使用者點選這個按鈕之後,就可以看到這些相關資訊在畫面中了。

在 Android 平台執行專案

  • 點選中間上方工具列的 [Windows Machine] 這個工具列按鈕旁的下拉選單三角形

  • 從彈出功能表中,找到 [Android Emulators] 內的任何一個模擬器

  • 接者,開始執行這個專案,讓他可以在 Android 模擬器出現

  • 此時,終於可以看到 [裝置螢幕資訊與Code Behind] 這個頁面了

  • 請點選 [取得螢幕畫素資訊] 按鈕

  • 將會看到底下資訊

  • 將這個螢幕旋轉 90 度

  • 請點選 [取得螢幕畫素資訊] 按鈕

  • 將會看到底下資訊

 






2022年8月11日 星期四

在 .NET MAUI 專案下,使用 LiveCharts2 套件,產生統計圖形

在 .NET MAUI 專案下,使用 LiveCharts2 套件,產生統計圖形

今天在 Twitter 上看到一個訊息,提到有個 LiveChart 元件,可以產生出統計圖形,並且是支援 .NET MAUI 開發平台的,覺得這樣的套件相當有趣與實用,因此,想說能否在 Prism.Maui 支援的環境下來使用,因此,就來進行測試,覺得效果相當的不錯。

建立 Prism.Maui 專案

  • 開啟 Visual Studio 2022 Preview 版本

  • 點選螢幕右下角的 [建立新的專案] 按鈕

  • 切換右上角的 [所有專案類型] 下拉選單控制項

  • 找到並且點選 [MAUI] 這個選項

  • 從清單中找到並選擇 [Prism .NET MAUI App (Dan Siegel)] 這個專案範本

    A project for creating a Prism .NET MAUI application for iOS, Android, Mac Catalyst, WinUI and Tizen

  • 點選右下角的 [下一步] 按鈕

  • 當出現了 [設定新的專案] 對話窗

  • 在 [專案名稱] 欄位內,輸入 mauiLiveChart

  • 點選右下角的 [建立] 按鈕

安裝相關 NuGet 套件

加入 PropertyChanged.Fody 的 NuGet 套件

  • 滑鼠右擊該專案的 [相依性] 節點
  • 從彈出功能表中選擇 [管理 NuGet 套件] 功能選項
  • 此時,[NuGet: PrismMonkey] 視窗將會出現
  • 點選 [瀏覽] 標籤頁次
  • 在左上方的搜尋文字輸入盒內輸入 PropertyChanged.Fody 關鍵字
  • 現在,將會看到 PropertyChanged.Fody 套件出現在清單內
  • 點選這個 PropertyChanged.Fody 套件
  • 點選右上方的 [安裝] 按鈕,安裝這個套件到這個專案內。

加入 LiveChartsCore.SkiaSharpView 的 NuGet 套件

  • 滑鼠右擊該專案的 [相依性] 節點
  • 從彈出功能表中選擇 [管理 NuGet 套件] 功能選項
  • 此時,[NuGet: PrismMonkey] 視窗將會出現
  • 點選 [瀏覽] 標籤頁次
  • 在左上方的搜尋文字輸入盒內輸入 LiveChartsCore.SkiaSharpView 關鍵字
  • 現在,將會看到 PropertyChanged.Fody 套件出現在清單內
  • 點選這個 PropertyChanged.Fody 套件
  • 點選右上方的 [安裝] 按鈕,安裝這個套件到這個專案內。

修正 MainPageViewModel

  • 在專案下,找到 [ViewModels] 資料夾
  • 找到並打開 [MainPageViewModel.cs] 檔案
  • 使用底下程式碼替換掉這個檔案內容
namespace mauiLiveChart.ViewModels;

using System.Collections.ObjectModel;
using System.ComponentModel;
using LiveChartsCore;
using LiveChartsCore.SkiaSharpView;
using Prism.Events;
using Prism.Navigation;
using Prism.Services;
public class MainPageViewModel : INotifyPropertyChanged, INavigationAware
{
    public event PropertyChangedEventHandler PropertyChanged;

    private readonly INavigationService navigationService;
    public ObservableCollection<ISeries> Series { get; set; } =
        new ObservableCollection<ISeries>();
    public MainPageViewModel(INavigationService navigationService)
    {
        this.navigationService = navigationService;

    }

    public void OnNavigatedFrom(INavigationParameters parameters)
    {
    }

    public void OnNavigatedTo(INavigationParameters parameters)
    {
        Series.Add(new PieSeries<double> { Values = new double[] { 2 } });
        Series.Add(new PieSeries<double> { Values = new double[] { 4 } });
        Series.Add(new PieSeries<double> { Values = new double[] { 1 } });
        Series.Add(new PieSeries<double> { Values = new double[] { 4 } });
        Series.Add(new PieSeries<double> { Values = new double[] { 3 } });
    }

}

在這個 ViewModel 內,宣告了一個 ObservableCollection<ISeries> Series { get; set; } 屬性,這裡將會要來產生這個圓餅圖需要用到的數據。

一旦這個頁面顯示之後,將會觸發與執行 OnNavigatedTo 這個方法,因此,在這裡進行這個圓餅圖要顯示相關數據資訊。

修正 MainPage

  • 在專案下,找到 [Views] 資料夾
  • 找到並打開 [MainPage.xaml] 檔案
  • 使用底下 XAML 標記替換掉這個檔案內容
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             Title="LiveChart2"
             xmlns:local="clr-namespace:mauiLiveChart.ViewModels"
             xmlns:lvc="clr-namespace:LiveChartsCore.SkiaSharpView.Maui;assembly=LiveChartsCore.SkiaSharpView.Maui"
             x:DataType="local:MainPageViewModel"
             x:Class="mauiLiveChart.Views.MainPage">

  <Grid BackgroundColor="White">
    <Label Text="Hello LiveChart2"
           Margin="10"
           FontSize="30"/>
    <lvc:PieChart
      Series="{Binding Series}">
    </lvc:PieChart>
  </Grid>
  
</ContentPage>

在這個 XAML 頁面內,僅簡單的加入兩個檢視控制項,一個 Label ,這個僅僅是用來標示用的,另外一個才是重點,一個 PieChart 檢視,用來顯示圓餅圖之用

進行測試與察看結果

  • 點選中間上方工具列的 [Windows Machine] 這個工具列按鈕旁的下拉選單三角形

  • 從彈出功能表中,找到 [Android Emulators] 內的任何一個模擬器

  • 接者,開始執行這個專案,讓他可以在 Android 模擬器出現

  • 此時,終於可以看到 [LiveChart2] 這個頁面了

若再 Android 進行開發與測試,若發現到無法看到上面的圓餅圖形,可以嘗試關閉 XAML 熱重載機制,請使用底下說明來關閉

  • 在功能表中,點選 [工具] > [選項]
  • 當 [選項] 對話窗出現之後
  • 點選 [偵錯] > [XAML 熱重新載入]
  • 取消 [啟用 XAML 熱重新載入] 這個檢查盒設定

再次重新執行,就會看到了