【问题标题】:Custom Control Styling/Triggers自定义控件样式/触发器
【发布时间】:2012-03-26 05:04:05
【问题描述】:

我正在尝试制作一个包含几个按钮和几个标签的自定义控件,但这些按钮应该是不可见的,只显示其中的内容。我可以通过将它们设置为透明来摆脱边框、背景等。但是每当我将鼠标悬停在它们上方时,默认的窗口悬停效果都会再次显示整个按钮。我已经尝试了许多关于自定义控件的指南,但最终无法弄清楚如何覆盖它。基本上我的问题归结为,有多少可以放在 generic.xaml 文件中,我必须在该文件中使用什么组织,以及这些样式应该去的其他地方吗?我确实意识到这是一个非常基本的问题,但这只是让我发疯,无法找出具体的答案。谢谢!

当前 xaml:

<Style TargetType="{x:Type local:TimePicker}">
    <Setter Property="Background" Value="Transparent" />
    <Setter Property="BorderBrush" Value="Transparent" />
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type local:TimePicker}">
                <Border Background="{TemplateBinding Background}"
                        BorderBrush="{TemplateBinding BorderBrush}"
                        BorderThickness="{TemplateBinding BorderThickness}"
                        Height="{TemplateBinding Height}"
                        Width="{TemplateBinding Width}">
                    <StackPanel Orientation="Horizontal">
                        <StackPanel x:Name="PART_Root"
                                    Orientation="Horizontal"
                                    HorizontalAlignment="Center">
                            <ToggleButton x:Name="PART_HourButton"
                                          HorizontalAlignment="Center"
                                          VerticalAlignment="Center"
                                          Margin="0"
                                          Background="Transparent"
                                          BorderBrush="Transparent"
                                          BorderThickness="0"
                                          Height="{Binding ElementName=PART_IncDecPanel, Path=ActualHeight}"
                                          Width="{Binding ElementName=PART_HourButton, Path=ActualHeight}"
                                          Content="{Binding RelativeSource={RelativeSource TemplatedParent},Path=Hour}">
                                                                    <ToggleButton.Triggers>
                                    <Trigger Property="IsMouseOver" Value="True">
                                        <Setter Property="Background" Value="Transparent" />
                                    </Trigger>
                                </ToggleButton.Triggers>
                            </ToggleButton>
                            <Label x:Name="PART_HourMinSeparator"
                                   HorizontalAlignment="Center"
                                   VerticalAlignment="Center"
                                   Margin="0"
                                   Content=":" />
                            <ToggleButton x:Name="PART_MinButton"
                                          HorizontalAlignment="Center"
                                          VerticalAlignment="Center"
                                          Margin="0"
                                          Background="Transparent"
                                          BorderBrush="Transparent"
                                          BorderThickness="0"
                                          Height="{Binding ElementName=PART_HourButton, Path=ActualHeight}"
                                          Width="{Binding ElementName=PART_HourButton, Path=ActualWidth}"
                                          Content="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Minute}" />
                            <StackPanel x:Name="PART_IncDecPanel" HorizontalAlignment="Center" VerticalAlignment="Center">
                                <Button x:Name="PART_IncreaseTime"
                                        Background="Transparent"
                                        BorderBrush="Transparent"
                                        BorderThickness="0"
                                        HorizontalAlignment="Center"
                                        HorizontalContentAlignment="Center"
                                        VerticalAlignment="Center"
                                        VerticalContentAlignment="Center"
                                        Margin="0"
                                        Padding="0"
                                        Width="22"
                                        Height="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=IncreaseImage.ActualHeight}">
                                    <Image Source="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=IncreaseImage}" />
                                </Button>
                                <Button x:Name="PART_DecreaseTime"
                                        Background="Transparent"
                                        BorderBrush="Transparent"
                                        BorderThickness="0"
                                        HorizontalContentAlignment="Center"
                                        HorizontalAlignment="Center"
                                        VerticalAlignment="Center"
                                        VerticalContentAlignment="Center"
                                        Margin="0"
                                        Padding="0"
                                        Height="{Binding ElementName=PART_IncreaseTime, Path=ActualHeight}"
                                        Width="{Binding ElementName=PART_IncreaseTime, Path=ActualWidth}">
                                    <Image Source="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=DecreaseImage}" />
                                </Button>
                            </StackPanel>
                        </StackPanel>
                    </StackPanel>
                </Border>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

【问题讨论】:

  • 如果您想要的按钮看起来不像按钮,并且当您将鼠标悬停在它们上时不会像按钮一样反应,那么您确定您真的想要按钮吗?但是对于您的问题,您将需要替换几乎整个按钮的默认模板。
  • 我是否在 generic.xaml 中这样做?我会在 ToggleButton 大纲中还是在其他地方这样做?
  • 与您的用户控制差不多。为您的 ToggleButton 设置样式。在那种风格中,使用 setter 来设置模板。在模板中只包含 ContentPresenter(如 flq 建议的那样),您最终会得到一个没有自己呈现的按钮。请记住,如果您决定保留模板的某些部分而不是全部(可能是选中时外观的变化),则必须在自己的模板中重新实现。

标签: wpf triggers styles custom-controls storyboard


【解决方案1】:

WPF 使用“无外观控件”,这基本上意味着您可以更改控件的整个可视部分(在设计或运行时),而无需更改其代码或该代码的行为。您已经使用此概念为您的 TimePicker 控件创建默认样式。如果您要从该样式中删除 ControlTemplate,您将在运行时看不到任何内容,因为控件本身只是 C# 或 VB 代码中定义的行为。

因为听起来您想要保留按钮的行为,但要完全改变外观,所以这是重新模板化的理想方案。这是一个非常简单的示例,它将仅显示内容(在 ContentPresenter 中):

<Button Content="Hello Template">
    <Button.Template>
        <ControlTemplate TargetType="{x:Type Button}">
            <ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
                                VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
        </ControlTemplate>
    </Button.Template>
</Button>

您可能希望在模板中添加更多内容,例如用于捕捉鼠标输入的透明边框以及一些触发器。您在示例中尝试在 ToggleButton 上使用 Trigger 的方式不正确(FrameworkElement Triggers 集合仅适用于 EventTriggers),但在 ControlTemplate 或 Style 内,该模式将起作用。

如果您想对 TimePicker ControlTemplate 中的每个按钮应用相同的样式,您可以将默认按钮样式添加到 ControlTemplate 的资源集合中:

<ControlTemplate TargetType="{x:Type MyControl}">
    <ControlTemplate.Resources>
        <Style TargetType="{x:Type Button}">
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type Button}">
                        <ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
                            VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </ControlTemplate.Resources>
    ...
</ControlTemplate>

【讨论】:

  • 好的,我的主要问题是不知道在层次结构中放置触发器的位置。感谢您的详细解释!
猜你喜欢
  • 1970-01-01
  • 2011-09-28
  • 2014-01-13
  • 2010-09-09
  • 2023-04-04
  • 1970-01-01
  • 2018-05-31
  • 1970-01-01
  • 2013-02-03
相关资源
最近更新 更多