Tài nguyên (resources)
Tài nguyên là các thông tin có thể được sử dụng lại áp dụng cho các điều khiển trên giao diện người dùng ví dụ như các mẫu định dạng (styles), mẫu điều khiển (control templates), các tham chiếu đối tượng (object references) hay mẫu dữ liệu (data templates). Xamarin.Forms hỗ trợ các mẫu định dạng (styles) và dữ liệu (data). Để tiện việc minh họa, chúng ta sẽ tạo một dự án Xamarin.Forms tên DataBinding.
Khai báo tài nguyên
Mỗi đối tượng trang (Page) hay bố cục (layout) chứa một thuộc tính gọi là Resources – một tập các tài nguyên XAML gồm một hay nhiều đối tượng kiểu ResourceDictionary. Một đối tượng ResourceDictionary chứa các tài nguyên XAML như định dạng, dữ liệu hay tham chiếu đối tượng. Ví dụ thêm một đối tượng ResourceDictionary đến Resources của trang (ContentPage) như sau:
<ContentPage.Resources> <ResourceDictionary> <!-- Add resources here --> </ResourceDictionary> </ContentPage.Resources>
Tài nguyên có phạm vi sử dụng, nghĩa là, tài nguyên ở mức trang thì có phạm vi sử dụng toàn trang và nếu tài nguyên ở mức layout thì chỉ có phạm vi sử dụng ở mức layout hiện tại. Ví dụ tài nguyên mức layout:
<StackLayout.Resources> <ResourceDictionary> <!—Tài nguyên chỉ tác dụng trong phạm vi layout này --> </ResourceDictionary> </StackLayout.Resources>
Nếu chúng ta muốn tài nguyên ảnh hưởng đến phạm vi toàn ứng dụng thì có thể sử dụng tập tin App.xaml:
<?xml version="1.0" encoding="utf-8" ?> <Application xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="DataBinding.App"> <Application.Resources> <!-- Application resource dictionary --> </Application.Resources> </Application>
Tài nguyên định dạng
Định nghĩa tài nguyên định dạng (Styles)
Trong nhiều trường hợp thiết kế giao diện các điều khiển, ví dụ Label hay Button, sẽ có cùng định dạng như kiểu chữ, cỡ chữ, màu chữ, v.v. Thay vì điều chỉnh các thuộc tính định dạng cho từng điều khiển chúng ta có thể sử dụng tài nguyên định dạng trong Xamarin.Forms.
Tài nguyên định dạng được định nghĩa trong phần tử <Style>:
<ResourceDictionary> <Style x:Key=... TargetType=...> <Setter Property=... Value=... /> <Setter Property=... Value=... /> <Setter Property=... Value=... /> ... </Style> </ResourceDictionary>
X:Key là chỉ danh xác định tài nguyên định dạng, TargetType xác định điều khiển dùng tài nguyên định dạng; các phần tử con Setter định nghĩa các thuộc tính định dạng như màu sắc, kiểu chữ, v.v. thông qua các thuộc tính Property và Value. Ví dụ sau đây định nghĩa một tài nguyên định dạng (trong App.xaml) màu chữ và kiểu chữ áp dụng cho các Label như sau:
<Application.Resources> <!-- Application resource dictionary --> <ResourceDictionary> <Style x:Key="labelStyle" TargetType="Label"> <Setter Property="TextColor" Value="Green" /> <Setter Property="FontSize" Value="Large" /> </Style> </ResourceDictionary> </Application.Resources>
Để sử dụng tài nguyên định dạng có chỉ danh labelStyle, chúng ta sẽ dùng thuộc tính Style và từ khóa StaticResource. Ví dụ trong tập tin MainPage.xaml có một Label mặc định như sau:
<?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:local="clr-namespace:DataBinding" x:Class="DataBinding.MainPage"> <Label Text="Welcome to Xamarin.Forms!" VerticalOptions="Center" HorizontalOptions="Center" /> </ContentPage>
Áp dụng tài nguyên labelStyle cho Label trên:
<Label Text="Welcome to Xamarin.Forms!" VerticalOptions="Center" HorizontalOptions="Center" Style="{StaticResource labelStyle}"/>
Kết quả:
Tính thừa kế (inheritance)
Các tài nguyên định dạng được hỗ trợ tính năng thừa kế nên chúng ta có thể định nghĩa một tài nguyên định dạng từ một tài nguyên định dạng khác nhờ thuộc tính BasedOn của Style. Ví dụ chúng ta định nghĩa tài nguyên có chỉ danh viewStyle như sau:
<Style x:Key="viewStyle" TargetType="View"> <Setter Property="HorizontalOptions" Value="Center" /> <Setter Property="VerticalOptions" Value="Center" /> </Style>
Tài nguyên viewStyle hướng đến một điều khiển trừu tượng gọi là View. Bây giờ chúng ta thay đổi lại nội dung của tài nguyên labelStyle bằng cách thêm thuộc tính BasedOn ở trên:
<Style x:Key="labelStyle" TargetType="Label" BasedOn="{StaticResource viewStyle}"> <Setter Property="TextColor" Value="Green" /> <Setter Property="FontSize" Value="Large" /> </Style>
Với BasedOn, chúng ta đã định nghĩa lại labelStyle kế thừa các thuộc tính định dạng từ viewStyle.
Label trong MainPage.xaml chúng ta viết lại như sau:
<Label Text="Welcome to Xamarin.Forms!" Style="{StaticResource labelStyle}"/>
Thực thi chương trình chúng ta vẫn nhận kết quả như hình trên.
Tài nguyên định dạng ngầm định
Trong trường hợp chúng ta muốn tài nguyên định dạng áp dụng đến mọi điều khiển cụ thể nào đó, ví dụ Label, thì chỉ cần định nghĩa phần tử <Style> không dùng thuộc tính x:Key. Ví dụ:
<Style TargetType="Label"> <Setter Property="TextColor" Value="Green" /> <Setter Property="FontSize" Value="Large" /> <Setter Property="HorizontalOptions" Value="Center" /> <Setter Property="VerticalOptions" Value="Center" /> </Style>
Với định nghĩa như trên, mọi điều khiển Label sẽ có chung định dạng về màu chữ (Green), cỡ chữ (Large) và vị trí (Center).
Tài nguyên không dùng x:Key gọi là tài nguyên ngầm định.
Tài nguyên dữ liệu
Một dạng tài nguyên quan trọng khác được hỗ trợ bởi Xamarin.Forms là tài nguyên dữ liệu. Cơ chế kết nối tài nguyên dữ liệu đến các điều khiển trong giao diện người dùng gọi là kết buộc dữ liệu (data binding). Cơ chế này hỗ trợ trên rất nhiều nền tảng của Microsoft chứ không riêng gì Xamarin.Forms.
Vì data binding là một chủ đề phức tạp nên để dễ hình dung chúng ta sẽ khảo sát một ví dụ phổ biến là kết buộc một thể hiện của lớp Person với các điều khiển trên giao diện người dùng. Để tạo lớp Person chúng ta chọn dự án DataBinding trong cửa sổ Solution Explorer:
Nhấn chuột phải vào dự án DataBinding chọn Add > New Item
Trong cửa sổ Add New Item chọn Class và nhập Person.cs trong Name
Nhấn Add. Xuất hiện tập tin Person.cs có nội dung:
using System; using System.Collections.Generic; using System.Text; namespace DataBinding { class Person { } }
Thêm các thành phần thành viên đến lớp Person như sau:
class Person { private string fullName; public string FullName { get { return fullName; } set { fullName = value; } } private DateTime dateOfBirth; public DateTime DateOfBirth { get { return dateOfBirth; } set { dateOfBirth = value; } } private string address; public string Address { get { return address; } set { address = value; } } }
Như vậy chúng ta đã có lớp Person. Bây giờ chúng ta sẽ tạo giao diện trong tập tin MainPage.xaml bằng cách thêm một layout là StackLayout chứa các điều khiển Label, Entry, DatePicker (xem lại cách dùng các điều khiển cơ bản trong Xamarin.Forms tại https://ngocminhtran.com/2018/07/21/cac-dieu-khien-trong-xamarin-forms/ ) như sau:
<StackLayout Orientation="Vertical" Padding="20"> <Label Text="Name:" /> <Entry /> <Label Text="Date of birth:"/> <DatePicker /> <Label Text="Address:"/> <Entry /> </StackLayout>
Nếu thực thi ứng dụng, giao diện như sau:
Các Label có định dạng như trên vì chúng ta đã định nghĩa tài nguyên định dạng trong App.xaml:
<Style TargetType="Label"> <Setter Property="TextColor" Value="Green" /> <Setter Property="FontSize" Value="Large" /> <Setter Property="HorizontalOptions" Value="Center" /> <Setter Property="VerticalOptions" Value="Center" /> </Style>
Lúc này, chúng ta khởi tạo dữ liệu cho một thể hiện của lớp Person bằng cách mở tập tin MainPage.xaml.cs và thực hiện tạo thể hiện lớp Person trong phương thức khởi tạo:
public MainPage() { InitializeComponent(); Person person = new Person(); person.FullName = "Minh"; person.DateOfBirth = DateTime.Now; person.Address = "Nha Trang"; }
Để hiển thị thông tin của thể hiện lớp Person trên đến các Entry trong giao diện chúng ta sẽ thực hiện cơ chế data binding theo hai bước:
- Bước 1: trở lại giao diện và kết hợp cú pháp Binding đến các thuộc tinh Text và Date của Entry và DatePicker như sau:
<Label Text="Name:" /> <Entry Text="{Binding FullName}"/> <Label Text="Date of birth:"/> <DatePicker Date="{Binding DateOfBirth, Mode=TwoWay}" /> <Label Text="Address:"/> <Entry Text="{Binding Address}"/>
Chúng ta dùng cú pháp {Binding PropertyName} là giá trị cho các thuộc tính Text và Date của Entry và DatePicker. PropertyName là các thuộc tính của lớp Person như FullName, DateOfBirth và Address. Chúng ta cũng cần lưu ý từ khóa Mode trong cấu trúc Binding của DatePicker cho phép chúng ta đọc ghi dữ liệu giữa giao diện và thể hiện lớp Person. Có 5 giá trị cho Mode:
- TwoWay: các điều khiển có thể đọc và ghi dữ liệu, ví dụ Entry
- OneWay: các điều khiển chỉ có thể đọc dữ liệu, ví dụ Label
- OneWayToSource: các điều khiển chỉ có thể ghi dữ liệu
- OneTime: các điều khiển có thể đọc dữ liệu chỉ một lần
- Default: phụ thuộc vào điều khiển
OneWay và TwoWay là hai chế độ phổ biến nhất.
- Bước 2: thực hiện kết buộc dữ liệu bằng cách dùng phương thức BindingContext trong phương thức khởi tạo cảu tập tin MainPage.xaml.cs như sau:
public MainPage() { InitializeComponent(); Person person = new Person(); person.FullName = "Minh"; person.DateOfBirth = DateTime.Now; person.Address = "Nha Trang"; this.BindingContext = person; }
Thực thi lại ứng dụng và xem kết quả:
Lời kết
Bài viết này chúng ta đã tìm hiểu khái quát về cách khai báo và sử dụng các tài nguyên định dạng và dữ liệu trong Xamarin.Forms. Chúng ta cũng đã tìm hiểu một ví dụ đơn giản về data binding. Trong bài viết kế tiếp chúng ta sẽ hiểu sâu hơn với data binding bằng cách kết nối giao diện với cơ sở dữ liệu SQLite.
Ý kiến bài viết