學習目標
- BindingContext 寫法
- binding 物件寫法
這是個重量級的章節... 直接影響到第 18 章的 MVVM...雖然不用 MVVM 程式還是能動,但實際使用後,程式上的維護會方便很多 (少了參數傳遞及顯示處理)。
Events 和 event handler 在 Xamarin 的互動介面中是很重要的一件事,但其實 參數傳遞 以及將 資料顯示於畫面,是一件相當繁瑣的事情。
舉例來說,今天我要將 Slider 的值顯示於 Label,必須控制 Slider 的 ValueChanged 方法,再取出 Slider 的值塞進 Label.Text,道道程序後才能完成這件事,相當繁瑣啊 !!!
能夠將 兩個物件的屬性 連結起來,不需要再 手動處理 物件之間的傳遞與顯示
舉例來說,今天我要將 Slider 的值顯示於 Label,必須控制 Slider 的 ValueChanged 方法,再取出 Slider 的值塞進 Label.Text,道道程序後才能完成這件事,相當繁瑣啊 !!!
有鑑於此,Xamairn 提供了一種強力的解決方案 -- Data Binding
能夠將 兩個物件的屬性 連結起來,不需要再 手動處理 物件之間的傳遞與顯示
data binding 一般來說都寫在 XAML 內。
DataBinding 最重要的概念就是 來源 (Source) 和 目標 (Target):
Target ← Source
來源 (Source) 是某個物件的屬性,其值改變時,同步去更新 目標 (Target) 屬性的值。
Binding basics
目標 (Target) 在 DataBinding 時其類別必須為 BindableProperty Object,Visual Element 就是 BindableProperty Object 。
來源 (Source) 除了是 物件 外,也可以是 C# 屬性,若為 C# 提供的來源,等值更改時要用 INotifyPropertyChanged 通知目標 (Target),也就是18 章要介紹的 MVVM。
Binding 會用到的類別、屬性和方法:
- 類別 - Binding
- 屬性 - BindingContext
- 方法 - SetBinding
- 類別 - BindableObjectExtension
XAML 會用到的擴充:
- BindingExtension
- ReferenceExtension
介面:
- INotifyPropertyChanged ( 定義於 System.ComponentModel namespace),用在屬性改變時發生通知。
- IValueConverter (定義於 Xamarin.Forms namespace),屬性之間數值型態轉換用。
不要緊張~ 以下會一一介紹~
Code & XAML
DataBinding 的 來源 (Source) 寫法有兩種:
- 利用 BindingContext 屬性
- 利用 bingding 物件
-- BindingContext --
.cs 寫法:
來源 (Source) 為 Slider 的 Value,目標 (Target) 為 Lable 的 Opacity,當拖曳 Slider 時會去同步更改 Lable 的透明度
public class OpacityBindingCodePage : ContentPage { public OpacityBindingCodePage() { Label label = new Label { Text = "Opacity Binding Demo", FontSize = Device.GetNamedSize(NamedSize.Large, typeof(Label)), VerticalOptions = LayoutOptions.CenterAndExpand, HorizontalOptions = LayoutOptions.Center }; Slider slider = new Slider { VerticalOptions = LayoutOptions.CenterAndExpand }; // 建立 Target 的 BindingContext -- 將 Source 放在一個準備區 label.BindingContext = slider; // 用 SetBinding 指定 Target 要更改的屬性 & 來源屬性名 label.SetBinding(Label.OpacityProperty, "Value"); // Construct the page. Padding = new Thickness(10, 0); Content = new StackLayout { Children = { label, slider } }; } }
XAML 寫法:
兩個新的擴充標籤出現!
- x:Reference - 設定 BindingContext
- Binding - 綁定要更改的屬性
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="OpacityBindingXaml.OpacityBindingXamlPage" Padding="10, 0"> <StackLayout> <Label Text="Opacity Binding Demo" FontSize="Large" VerticalOptions="CenterAndExpand" HorizontalOptions="Center" BindingContext="{x:Reference Name=slider}" Opacity="{Binding Path=Value}" /> <Slider x:Name="slider" VerticalOptions="CenterAndExpand" /> </StackLayout> </ContentPage>
可以將 XAML 縮短,省略 Name 和 Path
<Label Text="Opacity Binding Demo" FontSize="Large" VerticalOptions="CenterAndExpand" HorizontalOptions="Center" BindingContext="{x:Reference slider}" Opacity="{Binding Value}" />
-- binding 物件 --
.cs 寫法:
原理為先建立 binding 物件 (包含 Source 和 Path),再用 SetBinding() 綁入目標 (Target)。
宣告 binding 物件還有以下三種方法:
1. 設定 Binding Mode (下一小節介紹 )
2. 簡易寫法 (注意來源屬性放在前面 )
3. Create 泛型方法
public class BindingSourceCodePage : ContentPage { public BindingSourceCodePage() { Label label = new Label { Text = "Opacity Binding Demo", FontSize = Device.GetNamedSize(NamedSize.Large, typeof(Label)), VerticalOptions = LayoutOptions.CenterAndExpand, HorizontalOptions = LayoutOptions.Center }; Slider slider = new Slider { VerticalOptions = LayoutOptions.CenterAndExpand }; // 設定 binding 物件,並初始化 Source 和 屬姓名 Binding binding = new Binding { Source = slider, Path = "Value" }; // 將此 binding 物件綁入 Target label.SetBinding(Label.OpacityProperty, binding); // Construct the page. Padding = new Thickness(10, 0); Content = new StackLayout { Children = { label, slider } }; } }
宣告 binding 物件還有以下三種方法:
1. 設定 Binding Mode (下一小節介紹 )
Binding binding = new Binding("Value", BindingMode.Default, null, null, null, slider);
2. 簡易寫法 (注意來源屬性放在前面 )
Binding binding = new Binding("Value", source: slider);
3. Create 泛型方法
Binding binding = Binding.Create<slider>(src => src.Value); binding.Source = slider;
XAML 寫法:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="BindingSourceXaml.BindingSourceXamlPage" Padding="10, 0"> <StackLayout> <Label Text="Binding Source Demo" FontSize="Large" VerticalOptions="CenterAndExpand" HorizontalOptions="Center" Opacity="{Binding Source={x:Reference Name=slider}, Path=Value}" /> <Slider x:Name="slider" VerticalOptions="CenterAndExpand" /> </StackLayout> </ContentPage>
寫法上可將 Name 省略:
為什麼 來源 (Source) 會有兩種寫法?
Opacity="{Binding Source={x:Reference slider}, Path=Value}"
為什麼 來源 (Source) 會有兩種寫法?
最大的差異為
- BindingContext 底下的 子項目 能 共享 同一個 Source。舉例來說,在 StackLayout 內設定 BindingContext,所有 StackLayout 內的子項目都可以綁定這個 Source。
- binding 物件可針對 Target 的 單一屬性 做 獨立 Binding ~
共用 BindingContext 範例:
本範例會用到 WebView,WebView 類別可以在 App 內瀏覽網頁,也可以顯示 HTML,有兩個屬性可以設定,UrlWebVIewSource 和 HtmlWebViewSource。
WebView 定義了兩個方法,GoBack 和 GoForward,可以拿來實作上一頁和下一頁的按鈕。
本範例的功能就是要控制 上下頁 的按鈕能否使用 (最後一頁時下一頁按鈕就不行按)
可借助 WebView 兩個屬性,CanGoBack 和 CanGoForward 作為 Source,達到我們的目的 。
本範例的功能就是要控制 上下頁 的按鈕能否使用 (最後一頁時下一頁按鈕就不行按)
可借助 WebView 兩個屬性,CanGoBack 和 CanGoForward 作為 Source,達到我們的目的 。
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="WebViewDemo.WebViewDemoPage"> <ContentPage.Padding> <OnPlatform x:TypeArguments="Thickness" iOS="10, 20, 10, 0" Android="10, 0" WinPhone="10, 0" /> </ContentPage.Padding> <StackLayout> <Entry Keyboard="Url" Placeholder="web address" Completed="OnEntryCompleted" /> <!--BindingContext--> <StackLayout Orientation="Horizontal" BindingContext="{x:Reference webView}"> <!--Binding CanGoBack--> <Button Text="⇐" FontSize="Large" HorizontalOptions="FillAndExpand" IsEnabled="{Binding CanGoBack}" Clicked="OnGoBackClicked" /> <!--Binding CanGoForward--> <Button Text="⇒" FontSize="Large" HorizontalOptions="FillAndExpand" IsEnabled="{Binding CanGoForward}" Clicked="OnGoForwardClicked" /> </StackLayout> <WebView x:Name="webView" VerticalOptions="FillAndExpand" Source="https://xamarin.com" /> </StackLayout> </ContentPage>
.cs:
public partial class WebViewDemoPage : ContentPage { public WebViewDemoPage() { InitializeComponent(); } void OnEntryCompleted(object sender, EventArgs args) { webView.Source = ((Entry)sender).Text; } void OnGoBackClicked(object sender, EventArgs args) { webView.GoBack(); } void OnGoForwardClicked(object sender, EventArgs args) { webView.GoForward(); } }
執行結果:
這幾天一直在嘗試用DataBinding將C#中的變數連結,但數值都只在執行setBinding()這行程式時才會進行單次修改,毫無頭緒怎麼會完全沒有綁定的效果...
回覆刪除若你指的是 C# 屬性值更改時,前端也要跟著變動,或是前端輸入值後,C#的屬性值更改的話
刪除要使用 MVVM 的架構處理,可以參考這篇
http://www.loganedge.tw/2017/06/xamarinforms-mvvm.html