乐于分享
好东西不私藏

模板系统:ControlTemplate与DataTemplate详解

模板系统:ControlTemplate与DataTemplate详解

## 模板概述

Avalonia 有两种主要模板:
    **ControlTemplate** - 定义控件的视觉结构**DataTemplate** - 定义数据的显示方式

    ## ControlTemplate

    ### 基本概念

    ControlTemplate 替换控件的默认视觉结构:
    <Windowxmlns:https://github.com/avaloniaui">    <Window.Styles>        <StyleSelector="Button.custom">            <SetterProperty="Template">                <ControlTemplate>                    <BorderBackground="Blue"CornerRadius="15">                        <ContentPresenterContent="{TemplateBinding Content}"/>                    </Border>                </ControlTemplate>            </Setter>        </Style>    </Window.Styles>    <ButtonClasses="custom"Content="Custom Button"/></Window>

    ### TemplateBinding

    在模板中引用控件属性:
    <ControlTemplate>    <BorderBackground="{TemplateBinding Background}"            CornerRadius="{TemplateBinding CornerRadius}">        <ContentPresenterContent="{TemplateBinding Content}"/>    </Border></ControlTemplate>

    ## DataTemplate

    ### 基本概念

    DataTemplate 定义数据的展示方式:
    <ListBoxItemsSource="{Binding Users}">    <ListBox.ItemTemplate>        <DataTemplate>            <StackPanelOrientation="Horizontal">                <TextBlockText="{Binding Name}"/>                <TextBlockText="{Binding Age}"Margin="10,0,0,0"/>            </StackPanel>        </DataTemplate>    </ListBox.ItemTemplate></ListBox>

    ## 数据类型模板

    ### Typed DataTemplate

    public class UserTemplate : DataTemplate{    public override Control Build(object? data)    {        return new UserCard { User = data as UserModel };    }    public override bool Match(object? data)    {        return data is UserModel;    }}

    ### 注册模板

    <Windowxmlns:local="clr-namespace:MyApp">    <Window.Resources>        <local:UserTemplatex:Key="UserTemplate"/>    </Window.Resources>    <ListBoxItemTemplates="{Binding UserTemplate}"/></Window>

    ## 模板选择器

    ### DataTemplateSelector

    public class StatusTemplateSelector : IDataTemplateSelector{    public ITemplate<Control>? this[Type dataType] => null;    public Control? Build(object? data, Control scope, IDataTemplateHost? host)    {        if (data is OrderModel order)        {            return order.Status switch            {                OrderStatus.Pending => new PendingOrderTemplate(),                OrderStatus.Completed => new CompletedOrderTemplate(),                _ => new DefaultOrderTemplate()            };        }        return new TextBlock { Text = "Unknown" };    }    public bool Match(object? data, Control scope, IDataTemplateHost? host)    {        return data is OrderModel;    }}

    ## 模板中的控件

    ### ContentPresenter

    显示内容:
    <ControlTemplate>    <StackPanel>        <TextBlockText="Title"/>        <ContentPresenterContent="{TemplateBinding Content}"/>    </StackPanel></ControlTemplate>

    ### ItemsPresenter

    显示集合项:
    <ControlTemplate>    <Border>        <ItemsPresenter/>    </Border></ControlTemplate>

    ## 样式 vs 模板

    | 方面 | Style | ControlTemplate ||-----|-------|----------------|| 用途 | 设置属性 | 定义视觉结构 || 粒度 | 细粒度 | 粗粒度 || 灵活性 | 有限 | 完整替换 || 性能 | 轻量 | 较重 |
    **什么时候用模板?**
      需要完全替换控件外观需要添加额外的视觉元素样式无法满足需求

      ## 总结

      | 模板 | 用途 ||-----|------|| ControlTemplate | 定义控件的视觉结构 || DataTemplate | 定义数据的展示方式 || DataTemplateSelector | 动态选择模板 |
      **模板心法:**
        模板替换整个视觉结构数据模板控制列表项显示模板选择器实现条件渲染

        ## 下期预告

        下一篇文章我们将开始 **实战项目** 系列,用 Todo List 应用从设计到实现。

        相关学习资料