深入浅出WPF-11.Template(模板)03
阅读原文时间:2023年07月11日阅读:4

模板

如果把WPF窗体看做一个舞台的话,窗体上的控件就是演员,他们的职责就是在用户界面上按照业务逻辑的需呀哦扮演自己的角色。为了让同一个控件担当起不同的角色,程序员就要为他们设计多种外观样式和行为动作。这就是Style。构成Style 的两个重要元素就是Setter和Trigger,Setter是用来设置控件的静态外观风格,Trigger是用来设置控件的行为风格。

<Style x:Key="ListBoxOCTStyle" TargetType="{x:Type ListBox}">
        <Setter Property="Background" Value="{StaticResource ListBoxPopBackgroundBrush}" />
        <Setter Property="BorderBrush" Value="{StaticResource ListBoxPopBorderBrush}" />
        <Setter Property="BorderThickness" Value="0" />
        <Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Auto" />
        <Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Visible" />
        <Setter Property="ScrollViewer.CanContentScroll" Value="true" />
        <Setter Property="ScrollViewer.PanningMode" Value="Both" />
        <Setter Property="Stylus.IsFlicksEnabled" Value="False" />
        <Setter Property="VerticalContentAlignment" Value="Center" />
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type ListBox}">
                    <Border
                        Padding="1"
                        Background="{TemplateBinding Background}"
                        BorderBrush="{TemplateBinding BorderBrush}"
                        BorderThickness="{TemplateBinding BorderThickness}"
                        SnapsToDevicePixels="true">
                        <ScrollViewer
                            Padding="{TemplateBinding Padding}"
                            Focusable="false"
                            Template="{StaticResource ScrollViewerControlTemplate}">
                            <ItemsPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
                        </ScrollViewer>
                    </Border>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
        <Style.Resources>
            <Style BasedOn="{StaticResource ListBoxOCTItemStyle}" TargetType="ListBoxItem" />
        </Style.Resources>
    </Style>

根据上面的例子我们可以看出,如果想设置控件的ControlTemplate,只需要把Setter的Property设置为Template并为Value提供一个ControlTemplate对象即可。

Trigger(触发器)即当某些条件满足时会触发一个行为(比如某些值的变化或者动画的发生等),触发器比较像事件。事件一般是由用户操作触发的,而触发器除了事件触发型 的EventTrigger外,还有数据变化触发型的Trigger/DataTrigger及多条件触发型的MultiTrigger/MultiDataTrigger等。

1)基本触发器Trigger:类似于Setter,也有Property和Value两个属性,Property是Trigger关注的属性名称,Value是触发条件。一旦满足这个条件,对应的值就会被应用,触发条件不满足时,各属性值就会被还原。

<Style x:Key="ListBoxOCTItemStyle" TargetType="{x:Type ListBoxItem}">
        <Setter Property="Background" Value="Transparent" />
        <Setter Property="Width" Value="Auto" />
        <Setter Property="Height" Value="Auto" />
        <Setter Property="HorizontalContentAlignment" Value="{Binding Path=HorizontalContentAlignment, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}" />
        <Setter Property="VerticalContentAlignment" Value="{Binding Path=VerticalContentAlignment, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}" />
        <Setter Property="Padding" Value="0" />
        <Setter Property="BorderThickness" Value="0" />
        <Setter Property="BorderBrush" Value="{StaticResource ItemSelectedBackground}" />
        <Setter Property="ContentTemplate" Value="{StaticResource ListBoxItemOCTDataTemplate}" />
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type ListBoxItem}">
                    <Border
                        x:Name="Bd"
                        Margin="0,1"
                        Padding="{TemplateBinding Padding}"
                        Background="{StaticResource ItemSelectedBackground}"
                        BorderBrush="{StaticResource ItemSelectedBackground}"
                        BorderThickness="2,2,2,2"
                        CornerRadius="5"
                        SnapsToDevicePixels="true">
                        <Grid x:Name="grid">
                            <ContentPresenter
                                Margin="{TemplateBinding Padding}"
                                HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
                                VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
                                SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
                        </Grid>
                    </Border>
                    <ControlTemplate.Triggers>
                        <Trigger Property="IsMouseOver" Value="True">
                            <Setter Property="Background" Value="{StaticResource ItemSelectedBackground}" />
                            <Setter Property="Foreground" Value="{StaticResource CommonForeground}" />
                            <Setter TargetName="Bd" Property="BorderBrush" Value="YellowGreen" />
                            <Setter TargetName="Bd" Property="BorderThickness" Value="2,2,2,2" />
                        </Trigger>
                        <Trigger Property="IsSelected" Value="True">
                            <Setter Property="Background" Value="{StaticResource ItemSelectedBackground}" />
                            <Setter Property="Foreground" Value="{StaticResource CommonForeground}" />
                            <Setter TargetName="Bd" Property="BorderBrush" Value="#FF126BAA" />
                            <Setter TargetName="Bd" Property="BorderThickness" Value="2,2,2,2" />
                        </Trigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
        <Style.Triggers>
            <Trigger Property="IsMouseOver" Value="True">
                <!--<Setter Property="Background" Value="{StaticResource ItemSelectedBackground}"/>-->
                <!--<Setter Property="Foreground" Value="{StaticResource CommonForeground}"/>-->
                <!--<Setter Property="BorderBrush" Value="YellowGreen"/>
                <Setter Property="BorderThickness" Value="2,2,2,2"/>-->
            </Trigger>
            <Trigger Property="IsSelected" Value="True">
                <!--<Setter Property="Background" Value="{StaticResource ItemSelectedBackground}"/>-->
                <!--<Setter Property="Foreground" Value="{StaticResource CommonForeground}"/>-->
                <!--<Setter Property="BorderBrush" Value="#FF126BAA"/>-->
                <!--<Setter Property="BorderThickness" Value="2,2,2,2"/>-->
            </Trigger>
        </Style.Triggers>
    </Style>

2)MultiTrigger,类似于MultiBinding,只有多条件都满足时才会触发。MultiTrigger比Trigger多了一个Conditions属性,需要同时满足的条件就放在这个集合中。

<Style x:Key="DataGridScrollBarEverShowStyle" TargetType="DataGrid">
        <Setter Property="Background" Value="{DynamicResource SecondaryRegionBrush}" />
        <Setter Property="BorderBrush" Value="{DynamicResource BorderBrush}" />
        <Setter Property="BorderThickness" Value="0" />
        <Setter Property="GridLinesVisibility" Value="None" />
        <Setter Property="RowDetailsVisibilityMode" Value="VisibleWhenSelected" />
        <Setter Property="ScrollViewer.CanContentScroll" Value="True" />
        <Setter Property="ScrollViewer.PanningMode" Value="Both" />
        <Setter Property="VerticalScrollBarVisibility" Value="Visible" />
        <Setter Property="HorizontalScrollBarVisibility" Value="Visible" />
        <Setter Property="Stylus.IsFlicksEnabled" Value="False" />
        <Setter Property="EnableRowVirtualization" Value="True" />
        <Setter Property="CanUserAddRows" Value="False" />
        <Setter Property="CanUserDeleteRows" Value="False" />
        <Setter Property="CanUserReorderColumns" Value="False" />
        <Setter Property="CanUserResizeRows" Value="False" />
        <Setter Property="CanUserResizeColumns" Value="False" />
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="DataGrid">
                    <Border
                       ……
                    </Border>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
        <Style.Triggers>
            <MultiTrigger>
                <MultiTrigger.Conditions>
                    <Condition Property="IsGrouping" Value="true" />
                    <Condition Property="VirtualizingPanel.IsVirtualizingWhenGrouping" Value="false" />
                </MultiTrigger.Conditions>
                <Setter Property="ScrollViewer.CanContentScroll" Value="false" />
            </MultiTrigger>
        </Style.Triggers>
    </Style>

3)由数据触发的DataTrigger:程序中经常会遇到基于数据执行某些判断的情况,遇到这种情况时我们可以考虑使用DataTrigger。DataTrigger对象Binding属性会把数据源不断的送过来,一旦送来的值与Value值一致时,DataTrigger就会触发。

<!--  ItemsControl分组  -->
    <Style x:Key="GroupContainerStyle" TargetType="{x:Type GroupItem}">
        <Setter Property="HorizontalContentAlignment" Value="Center" />
        <Setter Property="VerticalContentAlignment" Value="Center" />
        <Setter Property="Width" Value="200" />
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type GroupItem}">
                    <ControlTemplate.Triggers>
                        <DataTrigger Binding="{Binding Path=IsBottomLevel}" Value="True">
                            <Setter TargetName="gridTemplate" Property="Grid.Background" Value="Gray" />
                        </DataTrigger>
                    </ControlTemplate.Triggers>
                    <Border BorderBrush="{StaticResource CommonBackground}" BorderThickness="0,2,0,0">
                        <Grid>
                            <Grid.RowDefinitions>
                                <RowDefinition />
                                <RowDefinition />
                            </Grid.RowDefinitions>
                            <Grid
                                x:Name="gridTemplate"
                                Width="{TemplateBinding Width}"
                                Height="40"
                                HorizontalAlignment="Center"
                                VerticalAlignment="Center"
                                Background="{StaticResource DarkBackground}">
                                <Border
                                    Height="Auto"
                                    Margin="0"
                                    HorizontalAlignment="Stretch"
                                    VerticalAlignment="Stretch"
                                    BorderBrush="Black"
                                    BorderThickness="0">
                                    <ToggleButton
                                        x:Name="btnShowHide"
                                        Width="Auto"
                                        Height="Auto"
                                        IsChecked="True"
                                        Style="{StaticResource ToggleButtonStyle}" />
                                </Border>
                                <!--<Label Content="{Binding Path=Name}" Grid.Column="0"  VerticalContentAlignment="Center"/>-->
                                <!--<Label VerticalContentAlignment="Center" HorizontalContentAlignment="Right" Grid.Column="1" Content="{Binding Path=ItemCount, StringFormat=Total:{0}}"/>-->
                            </Grid>
                            <ItemsPresenter
                                Grid.Row="1"
                                Margin="0"
                                Visibility="{Binding ElementName=btnShowHide, Path=IsChecked, Converter={StaticResource booleanToVisibilityConverter}}" />
                        </Grid>
                    </Border>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

4)多数据条件触发的MultiDataTrigger:当多个数据条件满足时就会触发的情况下,就可以使用多数据条件触发器。这里结合多条件触发器和数据触发器就可以很容易理解了。

5)事件触发器EventTrigger:事件触发器比较特殊,首先,他不是属性值或者数据的变化来触发而是由事件触发的;其次,被触发后并非应用一组Setter,而是执行一段动画

<ControlTemplate.Triggers>
                                        <EventTrigger RoutedEvent="MouseEnter">
                                            <BeginStoryboard Storyboard="{StaticResource Storyboard1}"/>
                                        </EventTrigger>
                                        <EventTrigger RoutedEvent="MouseLeave">
                                            <BeginStoryboard Storyboard="{StaticResource Storyboard2}"/>
                                        </EventTrigger>
                                    </ControlTemplate.Triggers>

有上面的这些代码可以看出,触发器不一定非要应用在Style中,在Template中也可以使用触发器。比如:

<ControlTemplate.Triggers>
                        <Trigger Property="IsMouseOver" Value="True">
                            <Setter Property="Background" Value="{StaticResource ItemSelectedBackground}" />
                            <Setter Property="Foreground" Value="{StaticResource CommonForeground}" />
                            <Setter TargetName="Bd" Property="BorderBrush" Value="YellowGreen" />
                            <Setter TargetName="Bd" Property="BorderThickness" Value="2,2,2,2" />
                        </Trigger>
                        <Trigger Property="IsSelected" Value="True">
                            <Setter Property="Background" Value="{StaticResource ItemSelectedBackground}" />
                            <Setter Property="Foreground" Value="{StaticResource CommonForeground}" />
                            <Setter TargetName="Bd" Property="BorderBrush" Value="#FF126BAA" />
                            <Setter TargetName="Bd" Property="BorderThickness" Value="2,2,2,2" />
                        </Trigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>