Thứ tư, ngày 7 tháng 12 năm 2016

WPF – Tùy biến TabControl

Ngày đăng: 28/3/2012, 9:5:35PM | Lượt xem: 50,818
Hot!

TabControl là loại control cho phép chứa các thành phần trong nhiều thẻ. Mỗi thẻ (hay TabItem) bao gồm hai phần chính là Header và Content.  Thông thường, phần Header chính là thứ bạn cần quan tâm khi muốn thay đổi giao diện của TabControl.

WPF - TabControl - Custom TabItemTabControl là loại control cho phép chứa các thành phần trong nhiều thẻ. Mỗi thẻ (hay TabItem) bao gồm hai phần chính là Header và Content.  Thông thường, phần Header chính là thứ bạn cần quan tâm khi muốn thay đổi giao diện của TabControl.

Giới thiệu

TabItem là một ContentControl nên bạn có thể thêm bất kì đối tượng vào thuộc tính Content của control này. Việc sử dụng một TabControl đơn giản chỉ là thêm các TabItem cùng với hai thuộc tính Header và Content của chúng.

Một TabControl bao gồm hai phần chính là:

- TabPanel: chứa header của các TabItem

- SelectedContent: vùng hiển thị nội dung của TabItem được chọn.

WPF TabControl

Khi tạo control template cho TabControl, bạn cần xác định vị trí của TabPanel bên trong. Có thể đặt nhiều TabPanel nhưng bạn cần chỉ ra TabPanel nào sẽ chứa các header của TabItem thông qua property TabPanel.IsItemsHost=True. Cùng với TabItem, bạn cần thêm một ContentPresenter để hiển thị nội dung của property SelectedContent.

…
<Window.Resources>
    <Style TargetType="{x:Type TabControl}">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="TabControl">
                    <DockPanel>
                        <TabPanel Height="20" DockPanel.Dock="Top" Background="BlanchedAlmond"/>
                        <TabPanel Height="20" DockPanel.Dock="Top" Background="Red" IsItemsHost="True"/>
                        <Grid Background="AliceBlue">
                            <ContentPresenter ContentSource="SelectedContent"/>
                        </Grid>
                    </DockPanel>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</Window.Resources>
<Grid>
    <TabControl>
        <TabItem Header="Lemon" />
        <TabItem Header="Orange"/>
    </TabControl>
</Grid>
…

Ví dụ trên tạo ra một TabControl với hai TabPanel như sau:

WPF - Custom TabControl

Tùy biến TabItem

Tạo template cho TabItem cũng tương tự như tạo cho TabControl, nhưng bạn cần gán ContentPresenter.ContentSource=”Header”:

<ControlTemplate TargetType="{x:Type TabItem}">
    <Grid>
        <Border x:Name="Border1"
                Background="{StaticResource LightBackgroundBrush}"
                BorderBrush="Blue"
                BorderThickness="1"
                CornerRadius="5,5,0,0" >
            <ContentPresenter
                ContentSource="Header"
                Margin="10,2,10,2"/>
        </Border>
    </Grid>
</ControlTemplate>

Tuy nhiên việc thiết kế này chưa hoàn chỉnh nên bạn không thể nhận ra sự khác biệt khi một TabItem được chọn hay không. Để làm được điều này, bạn cần sử dụng các trigger để thay đổi một số giá trị của Border mà tôi đã đặt tên là Border1 trong đoạn mã trên.

Ta sẽ tạo hai trigger cho hai giá trị của property TabItem.IsSelected, tương ứng với trạng thái được chọn hay không của các TabItem.

Các property của Border cần sửa trong ví dụ gồm có:

-      Margin: để thay đổi kích thước header (của TabItem).

-      BorderThickness: bỏ đường viền phía dưới header đang được chọn.

-      Background: thay đổi màu nền của các header.

Ngoài ra bạn cần sửa một property là Panel.ZIndex của TabItem:

-      Panel.Zindex: là một attached property, giá trị càng lớn thì TabItem sẽ được đưa lên phía trên các TabItem khác. Như vậy, ta cần đặt giá trị này của TabItem được chọn lớn hơn các TabItem khác.

Sau đó, tôi tạo một Style để áp dụng cho tất cả TabItem:

…
<Window.Resources>
    <!--LinearGradientBrush-->
    <LinearGradientBrush x:Key="LightBackgroundBrush" StartPoint="0,0" EndPoint="0,1">
        <LinearGradientBrush.GradientStops>
            <GradientStop Offset="0.4" Color="LightGoldenrodYellow"/>
            <GradientStop Offset="0.6" Color="BurlyWood"/>
        </LinearGradientBrush.GradientStops>
    </LinearGradientBrush>
    <!-- TabItem Style-->
    <Style TargetType="{x:Type TabItem}">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type TabItem}">
                    <Grid>
                        <Border x:Name="Border1" BorderBrush="Blue" CornerRadius="5,5,0,0" >
                            <ContentPresenter
                                ContentSource="Header"
                                Margin="10,2,10,2"/>
                        </Border>
                    </Grid>
                    <ControlTemplate.Triggers>
                        <Trigger Property="IsSelected" Value="False">
                            <Setter TargetName="Border1" Property="Margin" Value="0,5,0,0"/>
                            <Setter TargetName="Border1" Property="BorderThickness" Value="1" />
                            <Setter TargetName="Border1" Property="Background" Value="LightGray" />
                            <Setter Property="Panel.ZIndex" Value="1" />
                        </Trigger>
                        <Trigger Property="IsSelected" Value="True">
                            <Setter TargetName="Border1" Property="Margin" Value="-5,0,-5,0"/>
                            <Setter TargetName="Border1" Property="BorderThickness" Value="1,1,1,0" />
                            <Setter TargetName="Border1" Property="Background" Value="{StaticResource LightBackgroundBrush}" />
                            <Setter Property="Panel.ZIndex" Value="2" />
                        </Trigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</Window.Resources>
…

Kết quả:

WPF - TabControl - Custom TabItem

Tạo Closeable TabItem

Một số ứng dụng yêu cầu các TabControl có thể loại bớt các TabItem, bằng cách click Button đóng trên header của mỗi TabItem.

Để tạo Button đóng cho mỗi TabItem, bạn cần thiết kế trong control template. Các Button đóng này sẽ được xử lý sự kiện Click để tìm ra TabItem chứa nó và loại TabItem đó ra khỏi TabControl.

XAML:

…
<Window.Resources>
    <!--LinearGradientBrush-->
    <LinearGradientBrush x:Key="LightBackgroundBrush" StartPoint="0,0" EndPoint="0,1">
        <LinearGradientBrush.GradientStops>
            <GradientStop Offset="0.4" Color="LightGoldenrodYellow"/>
            <GradientStop Offset="0.6" Color="BurlyWood"/>
        </LinearGradientBrush.GradientStops>
    </LinearGradientBrush>
    <!-- TabItem Style-->
    <Style TargetType="{x:Type TabItem}">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type TabItem}">
                    <Border Background="{StaticResource LightBackgroundBrush}"
                            BorderBrush="Blue"
                            CornerRadius="5,5,0,0"
                            BorderThickness="1">
                        <StackPanel Orientation="Horizontal" Margin="2">

                            <ContentPresenter  ContentSource="Header" Margin="10,2,10,2"/>

                            <Button Background="Transparent" Style="{StaticResource {x:Static ToolBar.ButtonStyleKey}}"  Height="20" Width="20" Content="X" Click="tabItemCloseButton_Click"/>
                        </StackPanel>
                    </Border>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</Window.Resources>
<Grid>
    <TabControl Name="tabControl1">
        <TabItem Header="Lemon">
            <Image Height="200" Width="200" Source="Images\Lemon.jpg"/>
        </TabItem>
        <TabItem Header="Orange">
            <Image Height="200" Width="200" Source="Images\Orange.jpg"/>
        </TabItem>
        <TabItem Header="Polemo"/>
    </TabControl>
</Grid>
...

Phương pháp lấy được TabItem này dựa vào phương thức VisualTreeHelper.GetParent(). Phương thức này sẽ lấy thành phần cha của một DependencyObject trên VisualTree. Bằng cách sử dụng vòng lặp cho đến khi duyệt tới TabItem, ta sẽ có được đối tượng TabItem chứa Button được click.

C# code-behind:

// …
private void tabItemCloseButton_Click(object sender, RoutedEventArgs e)
{
    DependencyObject obj = sender as DependencyObject;

    while (!(obj is TabItem))
    {
        obj = VisualTreeHelper.GetParent(obj);
    }

    tabControl1.Items.Remove(obj);
}
// …

WPF - TabControl - Closeable TabItems

http://yinyangit.wordpress.com

Bài liên quan

 Chia sẻ qua: 
Hot!
Ý kiến bạn đọc

These items will be permanently deleted and cannot be recovered. Are you sure?

Gallery

image

Maecenas viverra rutrum pulvinar

Maecenas viverra rutrum pulvinar! Aenean vehicula nulla sit amet metus aliquam et malesuada risus aliquet. Vestibulum rhoncus, dolor sit amet venenatis porta, metus purus sagittis nisl, sodales volutpat elit lorem…

Read more

Text Links

Thiết kế logo chuyên nghiệp Insky
DAFABET
W88 w88b.com/dang-ky-tai-khoan-w88
W88
Copyright © 2011 - 2012 vietshare.vn by phamkhuong102@gmail.com doanhkisi2315@gmail.com. All rights reserved.