WPF – Data Template, Data Trigger và Template Selector

 

Data Template là kĩ thuật dùng để tạo ra một khuôn mẫu giao diện để hiển thị một phần tử dữ liệu trong collection. Mỗi phần tử dữ liệu có thể là một kiểu dữ liệu phức tạp và không phải bạn lúc nào cũng muốn dùng ToString() để hiển thị nó theo dạng chuỗi đơn giản. Thay vào đó, bạn có thể hiển thị nó theo một cách riêng, trên nhiều control, với định dạng khác nhau,…

Tạo một DataTemplate đơn giản

Tạo một collection cơ bản kiểu List<Person> để làm DataContext của Window.

public partial class Window1 : Window
{

    public Window1()
    {
        InitializeComponent();

        List<Person> persons = new List<Person>();
        persons.Add(new Person() { Age = 10, Name = "Yin" });
        persons.Add(new Person() { Age = 11, Name = "Yang" });
        persons.Add(new Person() { Age = 12, Name = "Yo" });

        this.DataContext = persons;

    }
}
public class Person
{
    public int Age { get; set; }
    public string Name { get; set; }
}

Trong ListBox, bạn tạo một DataTemplate và gán vào property ItemTemplate. Các control trong DataTemplate có thể binding đến các property của binding source được gắn vào ListBox. Ở đây tôi binding hai property Name và Age của đối tượng Person vào hai TextBlock trong DataTemplate.

<Window x:Class="DataTemplateExample.Window1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:DataTemplateExample"
        Title="DataTemplateExample" Height="300" Width="300"
>
    <Grid>
        <ListBox x:Name="listBox1" ItemsSource="{Binding}">
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <Border BorderThickness="1" BorderBrush="Green" Margin="2" Padding="5" Width="200" CornerRadius="3">
                        <Grid>
                            <Grid.ColumnDefinitions>
                                <ColumnDefinition/>
                                <ColumnDefinition/>
                                <ColumnDefinition/>
                            </Grid.ColumnDefinitions>
                            <TextBlock Grid.Column="0" Text="{Binding Path=Name}" Background="LightBlue"/>
                            <TextBlock Grid.Column="1" Text="  Age: "/>
                            <TextBlock Grid.Column="2" Text="{Binding Path=Age}" FontStyle="Italic"/>
                        </Grid>
                    </Border>
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>
    </Grid>
</Window>

Kết quả:

Tạo DataTemplate trong Resource

Bạn có thể định nghĩa DataTemplate trong phần Resouce để có thể sử dụng lại và làm code được rõ ràng.

<Window x:Class="DataTemplateExample.Window1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:DataTemplateExample"
        Title="DataTemplateExample" Height="300" Width="300"
>
        <Window.Resources>
        <DataTemplate x:Key="personTemplate">
        …
        </DataTemplate>
    </Window.Resources>
    <Grid>
        <ListBox x:Name="listBox1" ItemsSource="{Binding}" ItemTemplate="{StaticResource personTemplate}"/>
    </Grid>
</Window>

DataType property

Bằng cách sử dụng property DataType, bạn có thể để DataTemplate tự động được áp dụng cho một kiểu dữ liệu được chỉ định. Bằng cách này, bạn không cần dùng đến đặt x:Key cho DataTemplate.

<Window x:Class="DataTemplateExample.Window1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:DataTemplateExample"
        Title="DataTemplateExample" Height="300" Width="300"
>
    <Window.Resources>
        <DataTemplate DataType="{x:Type local:Person}">
       …
        </DataTemplate>
    </Window.Resources>
    <Grid>
        <ListBox x:Name="listBox1" ItemsSource="{Binding}"/>
    </Grid>
</Window>

Data Trigger

Nếu muốn định dạng riêng cho một phần tử trong collection dựa vào một số điều kiện, bạn có thể tạo một DataTrigger. Các DataTrigger được chứa trong property DataTemplate.Triggers. Mỗi DataTrigger chứa một collection các Setter dùng để gán giá trị cho các property của các control.

Với mỗi phần tử của collection, property DataTrigger.Value dùng để chứa giá trị so sánh với property tương ứng của phần tử được xác định trong DataTrigger.Binding. Để rõ ràng hơn, hãy xem ví dụ dùng để thiết lập màu chữ thành Red cho các ListBoxItem được gắn vào phần tử Person có Name là Yang.

<Window x:Class="DataTemplateExample.Window1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:DataTemplateExample"
        Title="DataTemplateExample" Height="300" Width="300"
>
    <Window.Resources>
        <DataTemplate DataType="{x:Type local:Person}">
            <Border BorderThickness="1" BorderBrush="Green" Margin="2" Padding="5" Width="200" CornerRadius="3">
                <Grid>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition/>
                        <ColumnDefinition/>
                        <ColumnDefinition/>
                    </Grid.ColumnDefinitions>
                    <TextBlock Grid.Column="0" Text="{Binding Path=Name}" Background="LightBlue"/>
                    <TextBlock Grid.Column="1" Text="  Age: "/>
                    <TextBlock Grid.Column="2" Text="{Binding Path=Age}" FontStyle="Italic"/>
                </Grid>
            </Border>
            <DataTemplate.Triggers>
                <DataTrigger Binding="{Binding Path=Name}" Value="Yang">
                    <Setter Property="ListBoxItem.Foreground" Value="Red"></Setter>
                </DataTrigger>
            </DataTemplate.Triggers>
        </DataTemplate>
    </Window.Resources>
    <Grid>
        <ListBox x:Name="listBox1" ItemsSource="{Binding}"/>
    </Grid>
</Window>

Kết quả:

Data Template Selector

Giống như DataTrigger nhưng DataTemplateSelector sẽ tạo ra các DataTemplate riêng để áp dụng cho mỗi phần tử của collection, thay vì gán giá trị mới cho các property để thay đổi cách hiển thị.

Bạn sử dụng kĩ thuật này bằng cách tạo một subclass của DataTemplateSelector và override phương thức SelectTemplate(). Phương thức này có kiểu trả về là một DataTemplate.

Ví dụ trong code-behind tôi tạo một lớp PersonHighlightTemplateSelector sau:

public class PersonHighlightTemplateSelector : DataTemplateSelector
{
    public override DataTemplate SelectTemplate(object item,
                                                DependencyObject container)
    {
        Person person = item as Person;
        FrameworkElement element = container as FrameworkElement;

        if(person!=null && element!=null)
        {
            if (person.Name=="Yang")
            {
                return  element.FindResource("HighlightTemplate") as DataTemplate;
            }
            else
            {
                return  element.FindResource("DefaultTemplate") as DataTemplate;
            }
        }

        return null;
    }
}

Tiếp tục trong tài liệu XAML sau tạo ra hai DataTemplate với Key là DefaultTemplate và HighlightTemplate, sau đó gán PersonHighlightTemplateSelector cho property ItemTemplateSelector của ListBox (kế thừa từ lớp ItemsControl).

<Window x:Class="DataTemplateExample.Window1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:DataTemplateExample"
        Title="DataTemplateExample" Height="300" Width="300"
>
    <Window.Resources>
        <DataTemplate x:Key="DefaultTemplate">
            <Border Margin="5" BorderThickness="1" BorderBrush="Gray" CornerRadius="4">
                <StackPanel Margin="5">
                    <TextBlock Text="{Binding Path=Name}"/>
                    <TextBlock Text="{Binding Path=Age}"/>
                </StackPanel>
            </Border>
        </DataTemplate>

        <DataTemplate x:Key="HighlightTemplate">
            <Border Margin="5" BorderThickness="1" BorderBrush="Blue" Background="LightBlue" CornerRadius="4">
                <StackPanel Margin="5">
                    <TextBlock Text="{Binding Path=Name}"/>
                    <TextBlock Text="{Binding Path=Age}"/>
                </StackPanel>
            </Border>
        </DataTemplate>
    </Window.Resources>
    <Grid>
        <ListBox Name="lstProducts" HorizontalContentAlignment="Stretch" ItemsSource="{Binding}">
            <ListBox.ItemTemplateSelector>
                <local:PersonHighlightTemplateSelector/>
            </ListBox.ItemTemplateSelector>
        </ListBox>
    </Grid>
</Window>

Kết quả:

https://yinyangit.wordpress.com

Related articles

Advertisements

6 thoughts on “WPF – Data Template, Data Trigger và Template Selector

  1. Pingback: Cơ bản về MVVM (Model – View – ViewModel) Pattern « Nguyễn Ngọc Vạn's Blog

  2. Pingback: Giới thiệu về MVVM (Model – View – ViewModel) Pattern « Cuộc Sống Và Khoa Học

  3. Pingback: Cơ bản về MVVM (Model – View – ViewModel) Pattern – nguyenleblog

Trả lời

Mời bạn điền thông tin vào ô dưới đây hoặc kích vào một biểu tượng để đăng nhập:

WordPress.com Logo

Bạn đang bình luận bằng tài khoản WordPress.com Đăng xuất / Thay đổi )

Twitter picture

Bạn đang bình luận bằng tài khoản Twitter Đăng xuất / Thay đổi )

Facebook photo

Bạn đang bình luận bằng tài khoản Facebook Đăng xuất / Thay đổi )

Google+ photo

Bạn đang bình luận bằng tài khoản Google+ Đăng xuất / Thay đổi )

Connecting to %s