Trước khi tiến hành thiết kế giao diện trong Windows Phone thì bạn cần hiểu cách sử Layout Control.
Layout control nó giống như bản vẽ kỹ thuật giúp ta dễ dàng tổ chức sắp xếp các control khác theo ý đồ thiết kế.
Windows phone hỗ trợ một số các Layout control phổ biến như sau:
- Grid Layout –Sắp xếp các đối tượng theo dòng và cột
- Canvas Layout- Sắp xếp các đối tượng theo tọa độ
- Stackpanel Layout– Sắp xếp các đối tượng theo cơ chế stack theo hướng từ trên dưới hoặc từ trái qua (tùy theo orientation)
- WrapPanel Layout– Sắp xếp các đối tượng theo dòng, khi nào hết chỗ chứa thì xuống dòng.
- Border Layout– Tạo đường viên bao bọc cho các đối tượng.
- ScrollView control– tạo Scrollview khi nội dung vượt quá khung chứa.
Mỗi một layout, control có những đặc tính và chức năng khác nhau. Tui sẽ lần lượt trình bày từng loại Layout, control:
1) Grid Layout
- Grid sắp xếp các thành phần con theo dòng và cột.
- Dễ dàng mở rộng nếu cần.
- Phải định nghĩa các dòng và cột trước khi dùng.
Bạn có thể tưởng tượng mỗi dòng của Grid layout giống như thẻ <tr> và mỗi cell của nó là thẻ <td> trong HTML.
Ví dụ ta muốn khai báo một Grid có 3 dòng 3 cột với thông số sau:
[code language=”xml”]
<Grid x:Name="LayoutRoot" >
<Grid.ColumnDefinitions>
<ColumnDefinition Width="150"/>
<ColumnDefinition Width="170"/>
<ColumnDefinition Width="160"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="150"/>
<RowDefinition Height="100"/>
<RowDefinition Height="200"/>
</Grid.RowDefinitions>
</Grid>
[/code]
– Dòng 1 có độ cao là 150, dòng 2 có độ cao là 100, dòng 3 có độ cao là 200
– Cột 1 có độ rộng là 150, cột 2 có độ rộng là 170 và cột 3 có độ rộng là 160
Ta xem kết quả:
Để đưa các control vào theo đúng dòng và cột ta làm như sau:
[code language=”xml”]
<Grid x:Name="LayoutRoot" >
<Grid.ColumnDefinitions>
<ColumnDefinition Width="150"/>
<ColumnDefinition Width="170"/>
<ColumnDefinition Width="160"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="150"/>
<RowDefinition Height="100"/>
<RowDefinition Height="200"/>
</Grid.RowDefinitions>
<Button Content="0,0" Grid.Row="0" Grid.Column="0"/>
<Button Content="0,1" Grid.Row="0" Grid.Column="1"/>
<Button Content="0,2" Grid.Row="0" Grid.Column="2"/>
<Button Content="1,0" Grid.Row="1" Grid.Column="0"/>
<Button Content="1,1" Grid.Row="1" Grid.Column="1"/>
<Button Content="1,2" Grid.Row="1" Grid.Column="2"/>
<Button Content="2,0" Grid.Row="2" Grid.Column="0"/>
<Button Content="2,1" Grid.Row="2" Grid.Column="1"/>
<Button Content="2,2" Grid.Row="2" Grid.Column="2"/>
</Grid>
[/code]
Ta thấy XAML ở trên sử dụng Attach Property Syntax để thiết lập giá trị thuộc tính cho các control.
Ví dụ:
<Button Content=”2,0″ Grid.Row=”2″ Grid.Column=”0″/>
Tức là đưa Button này vào dòng 2 (do Grid.Row=”2″) cột 0 (do Grid.Column=”0″).
Ta xem kết quả:
-Canvas sắp xếp vị trí các thành phần con dựa trên khoảng cách tuyệt đối từ thành phần đó đến lề trên (Canvas.Top) và trái (Canvas.Left) của canvas.
Chú ý:
– Top càng tăng thì đối tượng càng di chuyển xuống dưới, Top càng giảm thì đối tượng di chuyển lên trên.
– Left càng tăng thì đối tượng di chuyển qua phải, Left càng giảm thì đối tượng di chuyển qua trái.
ví dụ XAML:
[code language=”xml”]
<Canvas>
<Ellipse Name="myEllipse"
Canvas.Left="100"
Canvas.Top="70"
Width="100"
Height="100"
Fill="LawnGreen" />
</Canvas>
[/code]
Kết quả:
– Các thành phần con có thể nằm đè lên nhau, Khi đó, sử dụng thuộc tính ZIndex để đặt thứ tự xếp trên dưới cho các thành phần con:
[code language=”xml”]
<Canvas>
<Ellipse Canvas.Left="38" Canvas.Top="81" Canvas.ZIndex="2"
Width="100" Height="100" Fill="Green"/>
<Ellipse Canvas.Left="84" Canvas.Top="48"
Width="100" Height="100" Canvas.ZIndex="1" Fill="Yellow"/>
<Ellipse Canvas.Left="24" Canvas.Top="10"
Width="100" Height="100" Fill="Red" />
</Canvas>
[/code]
Kết quả:
Ta có thể di chuyển các đối tượng trên Canvas bằng coding behind như sau:
Tui đưa ra 1 ví dụ là cho phép 1 hình tròn di chuyển bất kỳ vị trí Top, Left trên màn hình.
bạn tạo 1 Project đặt tên MovingBall.
Bạn tạo MainPage.xaml như sau:
[code language=”xml”]
<phone:PhoneApplicationPage
x:Class="MovingBall.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
FontFamily="{StaticResource PhoneFontFamilyNormal}"
FontSize="{StaticResource PhoneFontSizeNormal}"
Foreground="{StaticResource PhoneForegroundBrush}"
SupportedOrientations="Portrait" Orientation="Portrait"
shell:SystemTray.IsVisible="True">
<Canvas HorizontalAlignment="Left" Height="768" VerticalAlignment="Top" Width="480">
<Ellipse x:Name="myBall" Height="100" Canvas.Left="153" Stroke="Black" Canvas.Top="10" Width="100">
<Ellipse.Fill>
<RadialGradientBrush GradientOrigin="0.5,0.75">
<GradientStop Color="Red" Offset="0"/>
<GradientStop Color="Green" Offset="1"/>
</RadialGradientBrush>
</Ellipse.Fill>
</Ellipse>
<Button x:Name="btnMove" Content="Move Ball" Canvas.Left="135" Canvas.Top="280"/>
</Canvas>
</phone:PhoneApplicationPage>
[/code]
Giao diện tạm thời nhưu sau:
– Bấm vào nút “Move Ball”: Nút này sẽ ẩn đi (tên là btnMove) và Ball (tên là myBall)sẽ di chuyển lung tung trên màn hình theo hướng từ trên xuống và xàng qua xàng lại từ trái qua phải,
– Khi nào Ball chạm đáy màn hình thì Button Move Ball hiển thị trở lại và Ball về vị trí cũ.
Ta tiến hành coding MainPage.xaml.cs như sau:
[code language=”csharp”]
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Navigation;
using Microsoft.Phone.Controls;
using Microsoft.Phone.Shell;
using MovingBall.Resources;
//thư viện để sử dụng DispatcherTimer
using System.Windows.Threading;
namespace MovingBall
{
public partial class MainPage : PhoneApplicationPage
{
// Constructor
public MainPage()
{
InitializeComponent();
// Sample code to localize the ApplicationBar
//BuildLocalizedApplicationBar();
}
//khai báo đối tượng DispatcherTimer để kích hoạt hẹn giờ
DispatcherTimer timer = new DispatcherTimer();
private void btnMove_Click(object sender, RoutedEventArgs e)
{
//cứ 100 mili giây thì thực hiện 1 lần
timer.Interval = new TimeSpan(0, 0, 0, 0, 100);
timer.Tick += timer_Tick;
timer.Start();
btnMove.Visibility = Visibility.Collapsed;
}
Random rd = new Random();
int top = 0, left = 0;
void timer_Tick(object sender, EventArgs e)
{
top+=rd.Next(0,20);
left = rd.Next(0, 400);
doMoveBall();
if(top>=600)
{
top = 0;
left = 0;
doMoveBall();
timer.Stop();
btnMove.Visibility = Visibility.Visible;
}
}
public void doMoveBall()
{
//Thiết lập qua trái -phải
Canvas.SetLeft(myBall, left);
//thiết lập từ trên xuống
Canvas.SetTop(myBall, top);
}
}
}
[/code]
3)Stackpanel Layout–
Sắp xếp các đối tượng theo cơ chế stack theo hướng từ trên dưới hoặc từ trái qua (tùy theo orientation)
[code language=”xml”]
<StackPanel x:Name="LayoutRoot" >
<Ellipse Width="100" Height="100" Fill="Green"/>
<Ellipse Width="100" Height="100" Fill="Yellow"/>
<Ellipse Width="100" Height="100" Fill="Red" />
</StackPanel>
[/code]
Ta xem kết quả:
Mặc định nó sẽ xếp theo chiều dọc từ trên xuống dưới, Ta dùng thuộc tính Orientation để sắp theo chiều ngang:
[code language=”xml”]
<StackPanel x:Name="LayoutRoot" Orientation="Horizontal">
<Ellipse Width="100" Height="100" Fill="Green"/>
<Ellipse Width="100" Height="100" Fill="Yellow"/>
<Ellipse Width="100" Height="100" Fill="Red"/>
</StackPanel>
[/code]
Ta xem kết quả:
Ta cũng có thể thay đổi vị trí thứ tự xuất của các control nằm bên trong Stackpanel bằng cách thay đổi FlowDirection=”RightToLeft” hoặc FlowDirection=”LeftToRight”.
Mặc định nó là FlowDirection=”LeftToRight”, nếu như ta đổi thành FlowDirection=”RightToLeft” thì hình trên thay đổi như sau:
[code language=”xml”]
<StackPanel x:Name="LayoutRoot"
Orientation="Horizontal"
FlowDirection="RightToLeft">
<Ellipse Width="100" Height="100" Fill="Green"/>
<Ellipse Width="100" Height="100" Fill="Yellow"/>
<Ellipse Width="100" Height="100" Fill="Red"/>
</StackPanel>
[/code]
4) WrapPanel Layout– Sắp xếp các đối tượng theo dòng, khi nào hết chỗ chứa thì xuống dòng.
– Để sử dụng được WrapPanel ta cần tải thư viện Windows Phone Toolkit về sau đó cấu hình namespace để sử dụng (cách khai báo namespace đã hướng dẫn ở các bài trước.
– Ta làm theo các bước sau:
Bước 1:
Bấm chuột phải vào Reference/ chọn Manage NuGet Packages…:
Bước 2:
Màn hình Manage NuGet Packages hiển thị ra như bên dưới đây, bạn chọn từng bước theo số thứ tự mà Tui đánh dấu:
số 1: Bạn click chọn Online trước
số 2: Bạn nhận từ khóa toolkit
Số 3: Bạn chọn gói Windows Phone Toolkit rồi bấm nút Install.
Sau khi bấn Install, hệ thống sẽ tiến hành tải và cài đặt… bạn cần chờ trong giây lát….:
Sau khi cài hoàn tất thì Windows Phone Toolkit sẽ được đánh dấu Tick tức là bạn bắt đầu sử dụng được: Tới bước trên là đã thành công, bạn bấm nút Close để trở về Project của mình, bạn thấy Project sẽ có một số thay đổi như sau:
(Bạn chỉ cần tải 1 lần mà thôi, các Project khác nếu như có sử dụng thư viện này thì bạn chỉ cần tham chiếu tới dll của nó là ok – Tui sẽ nói cách tham chiếu ở các bài tiếp sau này nếu các bạn chưa biết).
Bước 3:– Khai báo Namespace để sử dụng Windows Phone Toolkit.
trong phone:PhoneApplicationPage bạn khai báo sử dụng namespace như sau:
[code language=”xml”]
xmlns:toolkit="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone.Controls.Toolkit"
[/code]
Hình trên Tui chụp là cách sử dụng WrapPanel, bạn chỉ cần lấy prefix là toolkit (đặt tên gì là do bạn tuy nhiên cần mang tính gợi nhớ).
Để truy suất tới tất cả các thành phần thuộc Windows Phone Toolkit thì bạn chỉ cần viết
toolkit : [tên thành phần].
Windows phone toolkit cung cấp hàng loạt các control hữu ích sau (ta sẽ sử dụng rất nhiều trong các bài tập kế tiếp).
|
|
– Trước tiên ta sử dụng WrapPanel để layout các control:
Mặc định WrapPanel sắp xếp control theo hướng nằm ngang từ trái qua (Orientation=”Horizontal“) – tức là nếu như không thiết lập Orientation thì nó tự động là Horizontal, khi nào hết chỗ chứa thì nó tự động xuống dòng (ở đây tui thiết lập Orientation luôn):
[code language=”xml”]
<toolkit:WrapPanel Orientation="Horizontal">
<Ellipse Width="100" Height="100" Fill="Yellow"></Ellipse>
<Ellipse Width="100" Height="100" Fill="Yellow"></Ellipse>
<Ellipse Width="100" Height="100" Fill="Yellow"></Ellipse>
<Ellipse Width="100" Height="100" Fill="Yellow"></Ellipse>
<Ellipse Width="100" Height="100" Fill="Yellow"></Ellipse>
<Ellipse Width="100" Height="100" Fill="Yellow"></Ellipse>
<Ellipse Width="100" Height="100" Fill="Yellow"></Ellipse>
<Ellipse Width="100" Height="100" Fill="Yellow"></Ellipse>
<Ellipse Width="100" Height="100" Fill="Yellow"></Ellipse>
<Ellipse Width="100" Height="100" Fill="Yellow"></Ellipse>
<Ellipse Width="100" Height="100" Fill="Yellow"></Ellipse>
<Ellipse Width="100" Height="100" Fill="Yellow"></Ellipse>
</toolkit:WrapPanel>
[/code]
Nếu bạn thay bằng Orientation=”Vertical” thì các control sẽ được sắp từ trên xuống, khi nào hết cột thì chuyển qua cột mới:
<toolkit:WrapPanel Orientation=”Vertical”>
Và bạn cũng có thể thiết lập: FlowDirection=”RightToLeft” hay FlowDirection=”LeftToRight” để xem hướng xuất hiện, ví dụ bây giờ tui thiết lập FlowDirection=”RightToLeft” cho Wrapanel thì kết quả như sau:
<toolkit:WrapPanel Orientation=”Vertical” FlowDirection=”RightToLeft”>
5) Border Layout– Tạo đường viên bao bọc cho các đối tượng.
– Border không phải là một layout controls thật sự.
– Dùng để tạo khung cho các thành phần
– Thường được dùng làm khung cho Grid và StackPanel, WrapPanel, Canvas…. tùy…
Ví dụ ta xem hình Border layout dưới đây:
Tui có đoạn mã khuyết XAML dưới đây, bạn thử sửa lại cho hoàn thiện rồi tiến hành chạy (sửa mấy chỗ Tui để dấu chấm hỏi ???):
[code language=”xml”]
<Border BorderThickness="8,4,2,1" CornerRadius="50" >
<Border.BorderBrush>
<LinearGradientBrush EndPoint="0.5,1"
StartPoint="0.5,0">
<GradientStop Color="???" Offset="0"/>
<GradientStop Color="???" Offset="1"/>
</LinearGradientBrush>
</Border.BorderBrush>
<Grid x:Name="ContentPanel">
</Grid>
</Border>
[/code]
Bạn cần biết một vài thông số thường dùng của Border:
BorderThickness=”8,4,2,1″ –> Độ dày của đường viền (left=8, top=4, right=2, bottom=1)
BorderBrush –> màu của đường viền
CornerRadius –> Bo góc đường viền.
6) ScrollView control– tạo Scrollview khi nội dung vượt quá khung chứa.
[code language=”xml”]
<ScrollViewer Height="550">
<TextBlock>
[noi dung dai]
</TextBlock>
</ScrollViewer>
[/code]
Nếu muốn Scroll theo coding thì:
Dùng 2 phương thức ScrollToVerticalOffset() và ScrollToHorizontalOffset() để scrollviewer có thể scroll từng đoạn:
[code language=”csharp”]
private void btnScrollTop_Click(object sender, RoutedEventArgs e)
{
if (myscrollview.ScrollableHeight + myscrollview.VerticalOffset < myscrollview.ExtentHeight)
myscrollview.ScrollToVerticalOffset (5 + myscrollview.VerticalOffset);
}
private void btnScrollBottom_Click(object sender, RoutedEventArgs e)
{
if (myscrollview.VerticalOffset >=0)
myscrollview.ScrollToVerticalOffset (myscrollview.VerticalOffset-5);
}
[/code]
Với myscrollview là tên của ScrollView Như vậy Tui đã trình bày sơ sơ qua về một số Layout control rất cần thiết cho quá trình thiết kế giao diện, các bạn cần nghiên cứu nó kỹ, bài tập sau Tui sẽ trình bày về các control cơ bản như: Textbox, Textbloc, Button ….
Chúc các bạn thành công.
Tại mục 4) WrapPanel Layout
Bước 2: em đã cài đặt thành công toolkit rồi nhưng ở references nó không hiện ra như ở hình của thầy! giờ em phải làm sao đây thầy 🙁
thầy ơi, thay vì dùng scroll viewer để đọc truyện lượt xuống, em có cách nào vuốt ngang không thầy, dạ nghĩa là vuốt qua từng page thưa thầy