zoukankan      html  css  js  c++  java
  • 深入浅出WPF-11.Template(模板)01

    模板

    在WPF中,模板可以分为两大类:

    • 控件模板(ControlTemplate)是算法内容的表现形式,一个控件怎么组织其内部的结构才能让它更符合业务逻辑,让用户操作更舒服,都是由她控制的。它决定了控件长什么样子,并让程序员有机会在控件原有的内部逻辑基础上扩展自己的逻辑。

    • 数据模板(DataTemplate)是数据内容的表现形式,一条数据表现成什么样子,是简单的文本还是直观的图形动画就由他决定。

    我们先了解一下数据模板,同样一条数据比如拥有类Student实例,具有如下就一个字段:

    public class Student
        {
            /// <summary>
            /// 索引
            /// </summary>
            public int Id { get; set; }
            /// <summary>
            /// 姓名
            /// </summary>
            public string Name { get; set; }
            /// <summary>
            /// 性别
            /// </summary>
            public Sex Sex { get; set; }
            /// <summary>
            /// 出生日期
            /// </summary>
            public DateTime BirthDate { get; set; }
        }
    
        /// <summary>
        /// 性别
        /// </summary>
        public enum Sex : byte
        {
            /// <summary>
            /// 男
            /// </summary>
            Male = 0,
            /// <summary>
            /// 女
            /// </summary>
            Female = 1,
            /// <summary>
            /// 其他
            /// </summary>
            Other = 2,
        }
    

    这样的内容,在不同的控件中展示,展示的形式会不一样,这种模式称之为 数据-视图 模式。在WPF中,我们可以使用自定义控件UserControl来实现,也可以使用数据模板DataTemplate实现。

    DataTemplate常用在下面情况下:

    • ContentControl的ContentTemplate属性,相当与给ContentControl的内容穿衣服
    • ItemsControl 的ItemTemplate属性,相当远给ItemsControl的数据条目穿衣服
    • GridViewColumn的CellTemplate属性,相当于给GridViewColumn的单元格的数据穿衣服

    我么你先看一下一个程序的展示效果

    这里我们看一下代码实现:

    <UserControl
        x:Class="LpbPrj.Client.Views.ResultWideAreaImagingView"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:control="clr-namespace:LpbPrj.Client.Controls"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:hc="https://handyorg.github.io/handycontrol"
        xmlns:langs="clr-namespace:LpbPrj.Client.Properties.Langs"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:prism="http://prismlibrary.com/">
        <ListBox
            Margin="0,0,0,0"
            control:CustomeSelectionItems.SelectedItems="{Binding ResultSelectedItems}"
            BorderThickness="0"
            ItemsPanel="{StaticResource FluidMoveBehaviorWrapPanelItemsPanelTemplate}"
            ItemsSource="{Binding ResultList}"
            SelectedItem="{Binding Result}"
            SelectionMode="{Binding SelectionMode}"
            Style="{StaticResource WrapPanelHorizontalListBox}">
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <Grid>
                        <ContentControl prism:RegionManager.RegionName="ItemWideAreaImaging" />
                    </Grid>
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>
    </UserControl>
    

    在这个ListBox中,我们对其中的ItemTemplate穿衣服,这个衣服的内容是:

    <UserControl
        x:Class="LpbPrj.Client.Views.ItemWideAreaImaging"
        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:hc="https://handyorg.github.io/handycontrol"
        xmlns:langs="clr-namespace:LpbPrj.Client.Properties.Langs"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:prism="http://prismlibrary.com/">
        <hc:Card
            MaxWidth="240"
            Margin="8"
            BorderThickness="0"
            Effect="{StaticResource EffectShadow2}"
            Footer="{Binding}"
            Header="{Binding}">
            <hc:Card.HeaderTemplate>
                <DataTemplate>
                    <TextBlock
                        Margin="5"
                        Style="{StaticResource TextBlockDefault}"
                        Text="{Binding ExamType, Converter={StaticResource DtoShowStringConverter}}" />
                </DataTemplate>
            </hc:Card.HeaderTemplate>
            <Border CornerRadius="4,4,0,0" Style="{StaticResource BorderClip}">
                <Grid>
                    <Image Source="{Binding ImageThumbPath, Converter={StaticResource Path2BitmapImageConverter}}" Stretch="Uniform" />
                </Grid>
            </Border>
            <hc:Card.FooterTemplate>
                <DataTemplate>
                    <Grid>
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="*" />
                            <ColumnDefinition Width="Auto" />
                        </Grid.ColumnDefinitions>
                        <StackPanel
                            Grid.Column="0"
                            Margin="5"
                            Orientation="Horizontal">
                            <TextBlock
                                Style="{StaticResource TextBlockDefault}"
                                Text="{Binding ExamFileType, Converter={StaticResource DtoShowStringConverter}}"
                                TextTrimming="CharacterEllipsis"
                                TextWrapping="NoWrap" />
                            <TextBlock
                                Margin="10,0,0,0"
                                Style="{StaticResource TextBlockDefault}"
                                Text="{Binding ExamImageType, Converter={StaticResource ExamImageTypeConverter}}"
                                TextTrimming="CharacterEllipsis"
                                TextWrapping="NoWrap" />
                            <TextBlock
                                Margin="10,0,0,0"
                                Style="{StaticResource TextBlockDefault}"
                                Text="{Binding EyeType, Converter={StaticResource DtoShowStringConverter}}"
                                TextTrimming="CharacterEllipsis"
                                TextWrapping="NoWrap" />
                        </StackPanel>
                        <CheckBox
                            Grid.Column="1"
                            Width="30"
                            Height="30"
                            Margin="10,0,5,0"
                            IsChecked="{Binding IsSelected, RelativeSource={RelativeSource AncestorType={x:Type ListBoxItem}}}" />
                    </Grid>
                </DataTemplate>
            </hc:Card.FooterTemplate>
        </hc:Card>
    </UserControl>
    
    

    这段代码中的prism,我们暂且不管,但是主要内容还是能够理解的,我们使用了一个Card控件进行描述ListBox的展示内容,每个Card又通过TextBlock和CheckBox等控件进行描述。TextBlock中的对应的数据类型可能不能直接用于展示,比如枚举值,时间类型等。这里我们通过转化Converter来实现想要的展示形式。

    这里面存在一个认识的误区,在上面的代码中,我们认为ListBox的Items属性里面存放的是数据而不是控件。我们可以直接将ListBox的选中属性SelectedItem绑定到一个对应的数据实例中。这种模式叫做数据驱动模式。和我们之前使用的事件驱动模式不一样。事件驱动是控件和控件之间沟通或者说是形式和形式之间的沟通,而数据驱动则是数据与控件之间的沟通,是内容和形式之间的沟通。

    数据模板理解之后,我们再看一下控件模板ControlTemplate,我们可以使用披着羊皮的狼来理解控件模板,表面上看上去是羊,但是其实是狼。所以控件模板只是改变了控件的外形,不能改变控件的本质。对应控件外形的编辑我们推荐使用Blend。

    我们先看一个简单的Lable标签:

    <Style x:Key="LabelBaseStyle" TargetType="{x:Type Label}">
            <Style.Triggers>
                <Trigger Property="IsEnabled" Value="False">
                    <Setter Property="Opacity" Value="0.4" />
                </Trigger>
            </Style.Triggers>
            <Setter Property="Foreground" Value="{DynamicResource TextIconBrush}" />
            <Setter Property="Background" Value="{DynamicResource RegionBrush}" />
            <Setter Property="BorderBrush" Value="{DynamicResource BorderBrush}" />
            <Setter Property="CornerRadius" Value="{StaticResource DefaultCornerRadius}" />
            <Setter Property="Padding" Value="{StaticResource DefaultControlPadding}" />
            <Setter Property="HorizontalContentAlignment" Value="Center" />
            <Setter Property="VerticalContentAlignment" Value="Center" />
            <Setter Property="HorizontalAlignment" Value="Center" />
            <Setter Property="VerticalAlignment" Value="Center" />
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type Label}">
                        <Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" Padding="{TemplateBinding Padding}" SnapsToDevicePixels="true" CornerRadius="{Binding Path=(controls:BorderElement.CornerRadius), RelativeSource={RelativeSource TemplatedParent}}">
                            <ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" RecognizesAccessKey="True" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" />
                        </Border>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    

    我们对Lable标签的ControlTemplate进行修改,里面包含了一个控件Border,Border内部包含了控件的内容ContentPresenter。Border的属性通过绑定设置了BorderBrush="{TemplateBinding BorderBrush}" ,代表Border的BorderBrush属性需要绑定到Label的BorderBrush属性,两者保持一致。

  • 相关阅读:
    Debian 安装配置(包括kdevelop)
    linux matlab2016 安装
    Qt5.7 无法输入中文问题
    阻塞方法与InterruptedException
    java的null
    原子性、可见性、有序性与指令重排序
    物理机内存模型与java内存模型
    java构造函数总结
    什么时候需要用super
    重载与重写
  • 原文地址:https://www.cnblogs.com/vigorous/p/13408588.html
Copyright © 2011-2022 走看看