Monday, June 3, 2013

Pivot control mở rộng

Khi sử dụng pivot control trên Windows Phone 8, đôi khi tôi muốn ẩn đi tiêu đề của nó để có thêm “đất” hiển thị dữ liệu. Tuy nhiên pivot control có trong Windows Phone SDK không có khả năng ẩn/hiện này. Vì vậy tôi quyết định tạo một custom pivot control thực hiện công việc này.

Xây dựng một XAML custom control

Việc tạo một custom trong XAML là khá dễ dàng nếu bạn tuân theo đúng hướng dẫn. Nó yêu cầu bạn phải tạo thư mục Themes và trong thư mục đó tạo file có tên generic.xaml. generic.xaml là file resource, do đó không cần bất cứ file code behind nào. Hãy thực hiện việc đặt tên chính xác, bằng không control của bạn sẽ không làm việc. Bước tiếp theo là tạo một class thừa kế từ class ContentControl (hay một class đã thừa kế class ContentControl), cụ thể ở đây là class Pivot. Cấu trúc dự án ExtendedPivot sẽ trông như sau

Kiểu của dự án là Windows Phone Class Library. Nó chứa hai custom control, một cho pivot và một cho pivot item.

Mở rộng pivot control
    public class ExtendedPivot : Pivot
    {
        public static readonly DependencyProperty HeaderVisibilityProperty =
            DependencyProperty.Register("HeaderVisibilityProperty", typeof(Visibility), typeof(ExtendedPivot),
                new PropertyMetadata(null));

        public ExtendedPivot()
        {
            DefaultStyleKey = typeof (ExtendedPivot); // Set style of the control to the style defined in generic.xaml
        }

        public Visibility HeaderVisibility // Property to show/hide header of pivot
        {
            get { return (Visibility) GetValue(HeaderVisibilityProperty); }
            set { SetValue(HeaderVisibilityProperty, value); }
        }
    }

Chúng ta sẽ bắt đầu với constructor, dòng 9 nhất thiết phải có khi phát triển custom control, nó xác định style của control định nghĩa trong generic.xaml. Dòng 12-16 là property để xác định sự ẩn/hiển của tiêu đề. Dòng 3-5 đăng ký DependencyProperty để bind giá trị khi sử dụng control.

generic.xaml

Đây là style của ExtendedPivot control định nghĩa trong generic.xaml

    <Style TargetType="local:ExtendedPivot">
        <Setter Property="Margin" Value="0" />
        <Setter Property="Padding" Value="0" />
        <Setter Property="Foreground" Value="{StaticResource PhoneForegroundBrush}" />
        <Setter Property="Background" Value="Transparent" />
        <Setter Property="ItemsPanel">
            <Setter.Value>
                <ItemsPanelTemplate>
                    <Grid />
                </ItemsPanelTemplate>
            </Setter.Value>
        </Setter>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="local:ExtendedPivot">
                    <Grid HorizontalAlignment="{TemplateBinding HorizontalAlignment}" VerticalAlignment="{TemplateBinding VerticalAlignment}">
                        <Grid.RowDefinitions>
                            <RowDefinition Height="Auto" />
                            <RowDefinition Height="Auto" />
                            <RowDefinition Height="*" />
                        </Grid.RowDefinitions>
                        <Grid Grid.RowSpan="3" Background="{TemplateBinding Background}" />
                        <ContentControl Grid.Row="0"
                                        Margin="24,17,0,-7"
                                        HorizontalAlignment="Left"
                                        Content="{TemplateBinding Title}"
                                        ContentTemplate="{TemplateBinding TitleTemplate}"
                                        Visibility="{TemplateBinding HeaderVisibility}" />
                        <primitives:PivotHeadersControl x:Name="HeadersListElement" Grid.Row="1" />
                        <ItemsPresenter x:Name="PivotItemPresenter"
                                        Grid.Row="2"
                                        Margin="{TemplateBinding Padding}" />
                    </Grid>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

Đây là style của ExtendedPivotItem control định nghĩa trong generic.xaml

    <Style TargetType="local:ExtendedPivotItem">
        <Setter Property="Background" Value="Transparent" />
        <Setter Property="Padding" Value="0" />
        <Setter Property="HorizontalContentAlignment" Value="Stretch" />
        <Setter Property="VerticalContentAlignment" Value="Stretch" />
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="local:ExtendedPivotItem">
                    <Grid HorizontalAlignment="{TemplateBinding HorizontalAlignment}"
                          VerticalAlignment="{TemplateBinding VerticalAlignment}"
                          Background="{TemplateBinding Background}">
                        <VisualStateManager.VisualStateGroups>
                            <VisualStateGroup x:Name="Pivot">
                                <VisualState x:Name="Right" />
                                <VisualState x:Name="Left" />
                                <VisualState x:Name="Center" />
                            </VisualStateGroup>
                        </VisualStateManager.VisualStateGroups>
                        <ContentPresenter Margin="{TemplateBinding Padding}"
                                          HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
                                          VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
                                          Content="{TemplateBinding Content}"
                                          ContentTemplate="{TemplateBinding ContentTemplate}" />
                    </Grid>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

Cách tạo 2 style trên rất đơn giản. Bạn chỉ cần nhấn nút phải chuột trên control gốc tương ứng (ở đây là Pivot và PivotItem) trong cửa sổ Document Outline, chọn Edit Template, rồi Edit a Copy...

Style của ExtendedPivotItem giống hệt của PivotItem, trong khi style của ExtendedPivot có chút thay đổi so với của Pivot. Style của ExtendedPivot có thêm Visibility="{TemplateBinding HeaderVisibility}" để bạn có thể bind giá trị để ẩn/hiển tiêu đề của Pivot control.

Vậy là bạn đã hoàn thành ExtendedPivot control cho riêng mình.

Sử dụng ExtendedPivot control

Việc sử dụng ExtendedPivot control rất đơn giản. Đây là XAML code.

    <phone:PhoneApplicationPage
        x:Class="ExtendedPivot.Sample.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"
        xmlns:extendedPivot="clr-namespace:ExtendedPivot;assembly=ExtendedPivot"
        mc:Ignorable="d"
        FontFamily="{StaticResource PhoneFontFamilyNormal}"
        FontSize="{StaticResource PhoneFontSizeNormal}"
        Foreground="{StaticResource PhoneForegroundBrush}"
        SupportedOrientations="Portrait" Orientation="Portrait"
        shell:SystemTray.IsVisible="True">

        <!--LayoutRoot is the root grid where all page content is placed-->
        <Grid x:Name="LayoutRoot" Background="Transparent">
            <!--  Pivot Control  -->
            <extendedPivot:ExtendedPivot HeaderVisibility="{Binding Visibility}" Title="MY APPLICATION">
                <extendedPivot:ExtendedPivotItem Header="item 1">
                    <Grid>
                        <Button Click="ButtonBase_OnClick" Content="Toggle header" />
                    </Grid>
                </extendedPivot:ExtendedPivotItem>
                <extendedPivot:ExtendedPivotItem Header="item 2">
                </extendedPivot:ExtendedPivotItem>
            </extendedPivot:ExtendedPivot>
        </Grid>

    </phone:PhoneApplicationPage>

Còn đây là code C#

    public partial class MainPage : PhoneApplicationPage
    {
        private readonly MainViewModel _mainViewModel;

        public MainPage()
        {
            InitializeComponent();

            _mainViewModel = new MainViewModel();

            DataContext = _mainViewModel;
        }

        private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
        {
            _mainViewModel.Visibility = _mainViewModel.Visibility == Visibility.Collapsed
                ? Visibility.Visible
                : Visibility.Collapsed;
        }
    }

Và cuối cùng là view model

    public class MainViewModel : INotifyPropertyChanged
    {
        private Visibility _visibility;

        public Visibility Visibility
        {
            get { return _visibility; }
            set
            {
                if (_visibility == value) return;

                _visibility = value;

                OnPropertyChanged("Visibility");
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;

        protected virtual void OnPropertyChanged(string propertyName = null)
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
        }
    }

Source code của control và ví dụ sử dụng nó, các bạn có thể truy cập tại đây: http://bitbucket.agilehobo.com/wp-extended-pivot

Hy vọng qua bài viết này, các bạn có thể nắm được cơ bản về cách tạo một custom control cho Windows Phone.

No comments:

Post a Comment