Xamarin.Forms 之 XAML 設計預覽的設計時期資料
在前一篇文章 Xamarin.Forms 之 XAML 設計預覽 有說明,如何在 Visual Studio 2019 下,使用頁面預覽的功能,以便在進行 XAML 語言設計過程中,可以即時看到這些設計後的執行結果。
了解更多關於 [Xamarin.Android] 的使用方式
了解更多關於 [Xamarin.iOS] 的使用方式
了解更多關於 [Xamarin.Forms] 的使用方式
了解更多關於 [Hello, Android:快速入門] 的使用方式
了解更多關於 [Hello, iOS – 快速入門] 的使用方式
了解更多關於 [Xamarin.Forms 快速入門] 的使用方式
現在遇到一個問題,那就是通常在進行 XAML 設計的時候,都會使用 資料綁定 Data Binding 手法,與該頁面的 ViewModel 進行綁定再一起,可是,當使用這樣的設計方式的時候,又想要使用設計時期預覽功能,就會發現到有許多內容,還是需要在執行時期的時候,才能夠看到該頁面的執行結果。
為了解決這樣的問題,需要使用所謂的 [設計時期資料] 這樣的機制,需要使用 Xamarin.Forms 提供的新功能,首先,需要在 ContentPage 內加入底下的命名空間宣告,有了這些宣告,才能夠在 XAML 中使用設計時期資料的功能。
xmlns:d="http://xamarin.com/schemas/2014/forms/design"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
現在,可以將 MainPage.xaml 的內容修正成為如下所示,其中對於
Label Text="{Binding Message}" />
這個 XAML 標記,由於使用資料綁定來宣告,因此,這樣的用法只能夠在該專案執行的時候,才能夠看到該文字標籤顯示的內容;若想要在設計時期指定該 Label 這個文字標籤的 Text 屬性值,則需要使用 d: 這個命名空間來指定設計時期的屬性名稱,指定該設計時期的屬性值內容,如此,才能夠在設計階段在預覽畫面上看到這些內容,在此,要使用 <Label Text="{Binding Message}" d:Text="這是設計時期指定資料"/>
這樣的宣告語法。從下圖將會看到該 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:d="http://xamarin.com/schemas/2014/forms/design"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
x:Class="BlankApp5.Views.MainPage"
Title="{Binding Title}">
<StackLayout HorizontalOptions="CenterAndExpand" VerticalOptions="CenterAndExpand">
<Label Text="Welcome to Xamarin Forms and Prism!" />
<Label Text="{Binding Message}" />
<Label Text="{Binding Message}" d:Text="這是設計時期指定資料"/>
<BoxView Color="Blue" d:Color="Red"/>
</StackLayout>
</ContentPage>
可是,這個頁面在執行時期,將會顯成為這樣的情況,從這兩個畫面,可以看到當初指定在設計時期的 XAML 屬性值,是沒有影響到執行時期的 XAML 屬性值。
然而,對於像是 ListView 這樣的檢視,需要指定一個集合紀錄物件給 ItemsSource 這個使用,當然,最為方便的方式還是使用 ViewModel 來建立這樣的物件,並且透過資料綁定的方式指定給 ListView。
首先,在 ContentPage 內加入一個 XAML 命名空間,該命名空間將會指向該頁面的 ViewModel,在此,將會使用
xmlns:ViewModel="clr-namespace:BlankApp5.ViewModels"
這樣的宣告語法。接著,可以在該頁面內,使用 d: 命名空間,指定設計時期的該頁面之 BindingContext 屬性值,指向為 MainPageViewModel。 <d:ContentPage.BindingContext>
<ViewModel:MainPageViewModel/>
</d:ContentPage.BindingContext>
不過,這樣又產生一個問題,那就是原有的 ViewModel 類別中,沒有預設建構式存在,而會得到 :
XLS0507 類型 'MainPageViewModel' 無法用做為物件元素,因為它並非公用,或是未定義公用的無參數建構函式或類型轉換子
這樣的錯誤訊息。
因此,需要在 MainPageViewModel 類別中加入一個預設建構式,並且把 XAML 頁面修改成為底下的宣告,如此,就可以在設計時期,使用 Visual Studio 2019 的頁面預覽功能,看到 ListView 的設計時期呈現的樣貌了。
底下是執行螢幕截圖
<?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:d="http://xamarin.com/schemas/2014/forms/design"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
xmlns:ViewModel="clr-namespace:BlankApp5.ViewModels"
x:Class="BlankApp5.Views.MainPage"
Title="{Binding Title}">
<d:ContentPage.BindingContext>
<ViewModel:MainPageViewModel/>
</d:ContentPage.BindingContext>
<StackLayout HorizontalOptions="CenterAndExpand" VerticalOptions="CenterAndExpand">
<Label Text="Welcome to Xamarin Forms and Prism!" />
<Label Text="{Binding Message}" />
<Label Text="{Binding Message}" d:Text="這是設計時期指定資料"/>
<BoxView Color="Blue" d:Color="Red"/>
<ListView
ItemsSource="{Binding myItemList}"
>
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Label Text="{Binding Name}"
FontSize="20"/>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
</ContentPage>
using Prism.Commands;
using Prism.Mvvm;
using Prism.Navigation;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace BlankApp5.ViewModels
{
using System.Collections.ObjectModel;
using System.ComponentModel;
using Prism.Events;
using Prism.Navigation;
using Prism.Services;
public class MyModel : INotifyPropertyChanged
{
public string Name { get; set; }
public event PropertyChangedEventHandler PropertyChanged;
}
public class MainPageViewModel : INotifyPropertyChanged, INavigationAware
{
public event PropertyChangedEventHandler PropertyChanged;
public string Message { get; set; }
public ObservableCollection<MyModel> myItemList { get; set; } = new ObservableCollection<MyModel>();
private readonly INavigationService navigationService;
public MainPageViewModel()
{
Message = "Come From Default Constuctor !!";
myItemList.Add(new MyModel() { Name = "張三" });
myItemList.Add(new MyModel() { Name = "李四" });
myItemList.Add(new MyModel() { Name = "王五" });
}
public MainPageViewModel(INavigationService navigationService)
{
this.navigationService = navigationService;
Message = "Come From Injection Constructor";
myItemList.Add(new MyModel() { Name = "張三A" });
myItemList.Add(new MyModel() { Name = "李四B" });
myItemList.Add(new MyModel() { Name = "王五C" });
}
public void OnNavigatedFrom(INavigationParameters parameters)
{
}
public void OnNavigatedTo(INavigationParameters parameters)
{
}
public void OnNavigatingTo(INavigationParameters parameters)
{
}
}
}