Wpf 我应该在哪里定义和设置这些样式

Wpf 我应该在哪里定义和设置这些样式,wpf,custom-controls,datatrigger,Wpf,Custom Controls,Datatrigger,在下图中,您可以看到我当前正在创建的自定义控件,以便尽可能多地了解控件创建的整个过程 目前,我正试图通过有效地将重复的样式元素重构为单独的样式来简化xaml,并在图像所在的按钮被禁用时实现图像的禁用外观 在下面的xaml中,您可以看到我创建的按钮样式和图像的数据触发器。理论上,这两个按钮都被应用到左边的第二个按钮上,但很明显,它们没有被应用 我认为基本样式定义是正确的,但可能是它们位于错误的位置。有谁能告诉我我现在做错了什么 <ResourceDictionary xmlns="http

在下图中,您可以看到我当前正在创建的自定义控件,以便尽可能多地了解控件创建的整个过程

目前,我正试图通过有效地将重复的样式元素重构为单独的样式来简化xaml,并在图像所在的按钮被禁用时实现图像的禁用外观

在下面的xaml中,您可以看到我创建的按钮样式和图像的数据触发器。理论上,这两个按钮都被应用到左边的第二个按钮上,但很明显,它们没有被应用

我认为基本样式定义是正确的,但可能是它们位于错误的位置。有谁能告诉我我现在做错了什么

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                    xmlns:local="clr-namespace:ViewToLearn.WpfControls">


    <Style TargetType="{x:Type Image}">
        <Style.Triggers>
            <DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType={x:Type UIElement}, AncestorLevel=1}, Path=IsEnabled}"
                         Value="False">
                <Setter Property="Opacity"
                        Value="0.2"></Setter>
            </DataTrigger>
        </Style.Triggers>
    </Style>


    <Style TargetType="{x:Type Button}">
        <Setter Property="BorderBrush"
                Value="Transparent" />
        <Setter Property="Background"
                Value="Transparent" />
        <Setter Property="BorderThickness"
                Value="0" />
        <Setter Property="Margin"
                Value="4" />
    </Style>

    <Style TargetType="{x:Type local:VtlDataNavigator}">


        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type local:VtlDataNavigator}">
                    <StackPanel Orientation="Horizontal">
                        <Button BorderBrush="Transparent"
                                Background="Transparent"
                                BorderThickness="0">
                            <StackPanel Margin="4">
                                <Image Source="/ViewToLearn.WpfControls;component/Resources/Images/button_rounded_blue_first24.png" />
                            </StackPanel>
                        </Button> <!-- This is the button that should be influenced by the style and trigger defined above, but clearly it isn't -->
                        <Button IsEnabled="False">
                            <StackPanel Margin="4">
                                <Image Source="/ViewToLearn.WpfControls;component/Resources/Images/button_rounded_blue_previous24.png" />
                            </StackPanel>
                        </Button>
                        <TextBox Text="{Binding Path=RecordIndex,RelativeSource={RelativeSource TemplatedParent}}"
                                 VerticalAlignment="Center"
                                 IsReadOnly="True"
                                 BorderThickness="0"
                                 Margin="4" />
                        <TextBlock Text="of"
                                   VerticalAlignment="Center"
                                   Margin="4" />
                        <TextBlock Text="{Binding Path=RecordCount,RelativeSource={RelativeSource TemplatedParent}}"
                                   VerticalAlignment="Center"
                                   Margin="4" />
                        <Button BorderBrush="Transparent"
                                Background="Transparent"
                                BorderThickness="0">
                            <StackPanel Margin="4">
                                <Image Source="/ViewToLearn.WpfControls;component/Resources/Images/button_rounded_blue_next24.png" />
                            </StackPanel>
                        </Button>

您的第二个按钮有
IsEnabled=“false”
这就不同了

但是,如果您希望所有按钮的背景相同,无论是否启用,您必须进入触发器

使用触发器生成默认样式和模板的最佳方法是在窗口中放置一个虚拟/测试按钮,右键单击它,编辑模板/编辑副本。
VS将生成许多代码。您将看到按钮+触发器的“完整”模板

内部有一个触发器,用于在禁用时触发不同的外观:

<Setter Property="Template" >
    <Setter.Value>
        <ControlTemplate TargetType="{x:Type ButtonBase}">
            <Border x:Name="border" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" SnapsToDevicePixels="True">
                <ContentPresenter x:Name="contentPresenter" ContentTemplate="{TemplateBinding ContentTemplate}" Content="{TemplateBinding Content}" ContentStringFormat="{TemplateBinding ContentStringFormat}" Focusable="False" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}" RecognizesAccessKey="True" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
            </Border>
            <!-- ... -->
            <ControlTemplate.Triggers>
                <Trigger Property="IsEnabled" Value="False">
                    <Setter Property="Background" TargetName="border" Value="#FFF4F4F4"/>
                    <Setter Property="BorderBrush" TargetName="border" Value="#FFADB2B5"/>
                    <Setter Property="TextElement.Foreground" TargetName="contentPresenter" Value="#FF838383"/>
                </Trigger>
            </ControlTemplate.Triggers>
        </ControlTemplate>
    </Setter.Value>
</Setter>

这是一个模板,你可以从中获得灵感来更新你的风格(禁用时不触发):


关于代码的注释,因为您似乎渴望学习:

  • 不必为每个按钮设置背景、边框厚度和边框笔刷,它已经在您的
    按钮
    样式中完成
  • 每个
    图像周围的
    StackPanel
    是相同的,可以放在
    ContentPresenter
    标记周围的模板中
  • 如果
    VtlDataNavigator
    Usercontrol
    ,则可以将
    的所有内容放在
    标记内。
    它使控件更加可重用(不必在每个窗口中为控件提供模板)

  • 关于

    您的第二个按钮有
    IsEnabled=“false”
    这就不同了

    但是,如果您希望所有按钮的背景相同,无论是否启用,您必须进入触发器

    使用触发器生成默认样式和模板的最佳方法是在窗口中放置一个虚拟/测试按钮,右键单击它,编辑模板/编辑副本。
    VS将生成大量代码。您将看到按钮+触发器的“完整”模板

    内部有一个触发器,用于在禁用时触发不同的外观:

    <Setter Property="Template" >
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type ButtonBase}">
                <Border x:Name="border" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" SnapsToDevicePixels="True">
                    <ContentPresenter x:Name="contentPresenter" ContentTemplate="{TemplateBinding ContentTemplate}" Content="{TemplateBinding Content}" ContentStringFormat="{TemplateBinding ContentStringFormat}" Focusable="False" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}" RecognizesAccessKey="True" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
                </Border>
                <!-- ... -->
                <ControlTemplate.Triggers>
                    <Trigger Property="IsEnabled" Value="False">
                        <Setter Property="Background" TargetName="border" Value="#FFF4F4F4"/>
                        <Setter Property="BorderBrush" TargetName="border" Value="#FFADB2B5"/>
                        <Setter Property="TextElement.Foreground" TargetName="contentPresenter" Value="#FF838383"/>
                    </Trigger>
                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
    
    
    
    这是一个模板,你可以从中获得灵感来更新你的风格(禁用时不触发):

    
    
    关于代码的注释,因为您似乎渴望学习:

  • 不必为每个按钮设置背景、边框厚度和边框笔刷,它已经在您的
    按钮
    样式中完成
  • 每个
    图像周围的
    StackPanel
    是相同的,可以放在
    ContentPresenter
    标记周围的模板中
  • 如果
    VtlDataNavigator
    Usercontrol
    ,则可以将
    的所有内容放在
    标记内。
    它使控件更加可重用(不必在每个窗口中为控件提供模板)

  • 问候

    Emmanuel,感谢您全面的回答。关于你在底部的观点,我知道我不需要为每个按钮设置属性,这就是为什么我想要一个样式,但是在理论上应该设置为的一个按钮上,它没有被应用。它最初是一个用户控件,现在我想把它变成一个自定义控件,既学习如何做,又因为它应该更可重用。我怀疑我在Blend而不是VisualStudio中开始这项工作可能更好,但我知道,Blend我不知道。我现在将处理您的代码并向您报告。以下是我试图复制您显示的代码:。这应该会有帮助。只要你不需要动画,也不需要样本数据,混合就不是必要的。Emmanuel,谢谢你的全面回答。关于你在底部的观点,我知道我不需要为每个按钮设置属性,这就是为什么我想要一个样式,但是在一个按钮上,理论上它应该设置为t