WPF 基礎 - DataTemplate

若是把控件的功能視爲內容,則能夠使用控件模板 ControlTemplate 來控制它的展示;
若是把數據視爲內容,則能夠使用數據模板 DataTemplate 把數據展現出來;算法

ControlTemplate 是算法內容的表現形式,一個控件怎樣組織其內部結構才讓它更符合業務邏輯、讓用戶操做起來更舒服就是由它來控制的;
DataTemplate 是數據內容的表現形式,一條數據是簡單的文本仍是圖形動畫仍是其餘,由它決定。express

1. DataTemplate

1.1 一條柱狀圖的 DataTemplate 舉例

<DataTemplate x:Key="dt">
    <Grid>
        <StackPanel Orientation="Horizontal">
            <Grid>
                <Rectangle Width="{Binding Price}" Fill="LightSalmon"/>
                <TextBlock Text="{Binding Year}"></TextBlock>
            </Grid>
            <TextBlock Text="{Binding Price}"></TextBlock>
        </StackPanel>
    </Grid>
</DataTemplate>

1.2 經常使用 DataTemplate 的 3 處地方

ContentControl 的 ContentTemplate 屬性,給 ContentControl 的內容穿衣服;
ItemsControl 的 ItemTemplate 屬性,給 ItemsControl 的數據條目穿衣服;
GridViewColumn 的 CellTemplate 屬性,給 GridViewColumn 單元格里的數據穿衣服。動畫

1.3 使用 DataTemplate 實現一個汽車列表和詳情

<Window x:Class="WpfAppTemplate.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfAppTemplate"
        mc:Ignorable="d"
        Title="MainWindow" Height="350" Width="623">
    <Window.Resources>
        <local:NameToPhotoPathConverter x:Key="nameToPhotoPathConverter"/>
        
        <!--集合條目的內容模板-->
        <DataTemplate x:Key="carListItemViewTemplate">
            <Grid Margin="2">
                <StackPanel Orientation="Horizontal">
                    <Image Height="60" Width="64" 
                           Source="{Binding Name, Converter={StaticResource nameToPhotoPathConverter}}" />
                    <StackPanel Margin="5 12">
                        <TextBlock Text="Name" FontWeight="Bold"/>
                        <TextBlock Text="{Binding Name}"/>
                    </StackPanel>
                </StackPanel>
            </Grid>
        </DataTemplate>

        <!--詳情的內容模板-->
        <DataTemplate x:Key="carDetailViewTemplate">
            <Border BorderBrush="Black" BorderThickness="1" CornerRadius="6" Margin="2">
                <StackPanel Margin="5">
                    <Image Height="250" Width="400"
                           Source="{Binding Name, Converter={StaticResource nameToPhotoPathConverter}}" />
                    <StackPanel Orientation="Horizontal" Margin="5,0">
                        <TextBlock Text="Name:" FontWeight="Bold" FontSize="19"/>
                        <TextBlock Text="{Binding Name}" FontSize="19"/>
                    </StackPanel>
                    <StackPanel Orientation="Horizontal" Margin="5 0">
                        <StackPanel Orientation="Horizontal">
                            <TextBlock Text="Year:" FontWeight="Bold"/>
                            <TextBlock Text="{Binding Year}"/>
                        </StackPanel>
                        <StackPanel Orientation="Horizontal" Margin="5 0">
                            <TextBlock Text="TopSpeed:" FontWeight="Bold"/>
                            <TextBlock Text="{Binding TopSpeed}"/>
                        </StackPanel>
                    </StackPanel>
                </StackPanel>
            </Border>
        </DataTemplate>
    </Window.Resources>
    
    <Grid>        
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="5*"/>
            <ColumnDefinition Width="2*"/>
        </Grid.ColumnDefinitions>

        <UserControl x:Name="carDetailControl" 
                     ContentTemplate="{StaticResource carDetailViewTemplate}" 
                     Content="{Binding ElementName=listBoxCar, Path=SelectedItem}" />

        <ListBox Grid.Column="1" x:Name="listBoxCar" Margin="2" 
                 ItemTemplate="{StaticResource carListItemViewTemplate}" />   
    </Grid>
</Window>

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        InitializeList();
    }

    /// <summary>
    /// 添加汽車種類
    /// </summary>
    void InitializeList()
    {
        List<Car> carList = new List<Car>();
        carList.Add(new Car() { Name = "BMW", TopSpeed = "260", Year = "1997" });
        carList.Add(new Car() { Name = "Audi", TopSpeed = "240", Year = "1999" });
        carList.Add(new Car() { Name = "Toyota", TopSpeed = "120", Year = "2016" });
        carList.Add(new Car() { Name = "Volkswagen", TopSpeed = "150", Year = "2000" });

        this.listBoxCar.ItemsSource = carList;
    }
 }

1.4 而若是不用 DataTemplate ,就會顯得比較繁瑣且冗長

使用 winform 的 Usercontrol 實現一個汽車列表和詳情this

<!--汽車詳情-->
<UserControl x:Class="WpfAppTemplate.UserControls.CarDetailUserControl"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:WpfAppTemplate.UserControls"
             mc:Ignorable="d" >
    <Border BorderBrush="Black" BorderThickness="1" CornerRadius="6" Margin="2"> 
        <StackPanel Margin="5">
            <Image x:Name="img" Height="250" Width="400"/>

            <StackPanel Orientation="Horizontal" Margin="5,0">
                <TextBlock Text="Name:" FontWeight="Bold" FontSize="19"/>
                <TextBlock x:Name="textBlockName" FontSize="19"/>
            </StackPanel>

            <StackPanel Orientation="Horizontal" Margin="5 0">
                <StackPanel Orientation="Horizontal">
                    <TextBlock Text="Year:" FontWeight="Bold"/>
                    <TextBlock x:Name="textBlockYear"/>
                </StackPanel>
                <StackPanel Orientation="Horizontal" Margin="5 0">
                    <TextBlock Text="TopSpeed:" FontWeight="Bold"/>
                    <TextBlock x:Name="textBlockTopSpeed"/>
                </StackPanel> 
            </StackPanel>
            
        </StackPanel>
    </Border>
</UserControl>

public partial class CarDetailUserControl : UserControl
{
    public CarDetailUserControl()
    {
        InitializeComponent();
    }

    Car _currentCar;
    public Car CurrentCar
    {
        get { return _currentCar; }
        set
        {
            if (value == null) return;
            _currentCar = value;
            this.textBlockName.Text = value.Name;
            this.textBlockTopSpeed.Text = value.TopSpeed;
            this.textBlockYear.Text = value.Year;
            string uriStr = string.Format(@"/Resources/Images/Cars/{0}.jpg", value.Name);
            this.img.Source = new BitmapImage(new Uri(uriStr, UriKind.Relative));
        }
    }        
}

<!--汽車條目-->
<UserControl x:Class="WpfAppTemplate.UserControls.CarListItemUserControl"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:WpfAppTemplate.UserControls"
             mc:Ignorable="d">
    <Grid Margin="2">
        <StackPanel Orientation="Horizontal">
            <Image x:Name="img" Height="60" Width="64"/>
            <StackPanel Margin="5 12">
                <TextBlock Text="Name" FontWeight="Bold"/>
                <TextBlock x:Name="textBlockName" />
            </StackPanel>
        </StackPanel>
    </Grid>
</UserControl>

public partial class CarListItemUserControl : UserControl
{
    public CarListItemUserControl()
    {
        InitializeComponent();
    }

    Car _currentCar;
    public Car CurrentCar
    {
        get { return _currentCar; }
        set
        {
            if (value == null) return;

            _currentCar = value;
            this.textBlockName.Text = value.Name;
            string uriStr = string.Format(@"/Resources/Images/Cars/{0}.jpg", value.Name);
            this.img.Source = new BitmapImage(new Uri(uriStr, UriKind.Relative));
        }
    }
}

<!--主窗體-->
<Window x:Class="WpfAppTemplate.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfAppTemplate"
        xmlns:localUserControls="clr-namespace:WpfAppTemplate.UserControls"
        mc:Ignorable="d"
        Title="MainWindow" Height="350" Width="623">
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="5*"/>
            <ColumnDefinition Width="2*"/>
        </Grid.ColumnDefinitions>

        <localUserControls:CarDetailUserControl x:Name="carDetailControl"/>

        <ListBox Grid.Column="1" x:Name="listBoxCar" SelectionChanged="listBoxCar_SelectionChanged" Margin="2"/>
    </Grid>
</Window>

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        InitializeList();
    }

    /// <summary>
    /// 添加汽車種類
    /// </summary>
    void InitializeList()
    {
        List<Car> carList = new List<Car>();
        carList.Add(new Car() { Name = "BMW", TopSpeed = "260", Year = "1997" });
        carList.Add(new Car() { Name = "Audi", TopSpeed = "240", Year = "1999" });
        carList.Add(new Car() { Name = "Toyota", TopSpeed = "120", Year = "2016" });
        carList.Add(new Car() { Name = "Volkswagen", TopSpeed = "150", Year = "2000" });

        // 給每種汽車生成一個 汽車條目控件,做爲一條內容添加到汽車列表控件的內容集合
        foreach (Car car in carList)
        {
            CarListItemUserControl control = new CarListItemUserControl();
            control.CurrentCar = car;
            this.listBoxCar.Items.Add(control);
        }
    }

    /// <summary>
    /// 當切換汽車時
    /// </summary>
    /// <param name="sender">listbox</param>
    /// <param name="e">SelectionChangedEventArgs, 能夠經過 AddedItems 參數取到新選擇的項</param>
    private void listBoxCar_SelectionChanged(object sender, SelectionChangedEventArgs e)
    {
        CarListItemUserControl control = e.AddedItems[0] as CarListItemUserControl;
        if (control != null)
        {
            this.carDetailControl.CurrentCar = control.CurrentCar;
        }
    }
}
相關文章
相關標籤/搜索