WPF - 有没有办法在 ControlTemplate 的触发器中定位元素类型?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/28034009/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-13 12:51:46  来源:igfitidea点击:

WPF - Is there a way to target an element type in a ControlTemplate's trigger?

wpfxamltriggerscontroltemplatetargettype

提问by mikelt21

I have the following ControlTemplate defined:

我定义了以下 ControlTemplate:

<ControlTemplate x:Key="buttonTemplate" TargetType="{x:Type Button}">
    <Border x:Name="buttonBorder">
        <Grid>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="Auto"/>
                <ColumnDefinition Width="Auto"/>
            </Grid.ColumnDefinitions>
            <TextBlock x:Name="txtLabel" Grid.Column="0">
                <ContentPresenter/>
            </TextBlock>
            <Canvas x:Name="reschedule" Grid.Column="1">
                <Path x:Name="path1" ... />
                <Path x:Name="path2" ... />
                <Path x:Name="path3" ... />
                <Path x:Name="path4" ... />
                <Path x:Name="path5" ... />
                <Path x:Name="path6" ... />
                <Path x:Name="path7" ... />
                <Path x:Name="path8" ... />
                <Path x:Name="path9" ... />
                <Path x:Name="path10" ... />
            </Canvas>
        </Grid>
    </Border>
    <ControlTemplate.Triggers>
        <Trigger Property="IsMouseOver" Value="True">
            <Setter TargetName="buttonBorder" Property="Background" Value="DarkGreen"/>
        </Trigger>
        <Trigger Property="IsEnabled" Value="False">
            <Setter TargetName="buttonBorder" Property="Background" Value="DarkGray"/>
            <Setter TargetName="txtLabel" Property="Foreground" Value="Gray"/>
        </Trigger>
    </ControlTemplate.Triggers>
</ControlTemplate>

Right now the default TextBlockForegroundand PathFillproperties have been set to White. When the button is disabled I want to set those properties to Gray. Right now it works for the TextBlockand I can make it work for the Paths too by targetting each of their names, but is there a way to target all the Pathelements by type? Something like:

现在默认值TextBlockForegroundPathFill属性已设置为White. 当按钮被禁用时,我想将这些属性设置为Gray. 现在它适用于sTextBlock并且我也可以Path通过定位它们的每个名称来使其适用于s ,但是有没有办法Path按类型定位所有元素?就像是:

<Setter TargetType="Path" Property="Fill" Value="Gray"/>

I've tried adding the following trigger to the Borderelement's style but it doesn't work:

我已经尝试将以下触发器添加到Border元素的样式中,但它不起作用:

<Border.Style>
    <Style TargetType="Border">
        <Style.Resources>
            <Style TargetType="Path">
                <Style.Triggers>
                    <Trigger Property="IsEnabled" Value="False">
                        <Setter Property="Fill" Value="Gray"/>
                    </Trigger>
                </Style.Triggers>
            </Style>
        </Style.Resources>
    </Style>
</Border.Style>

采纳答案by Anatoliy Nikolaev

You can try this trick:

你可以试试这个技巧:

Create a proxy control for Binding:

为以下对象创建代理控件Binding

<Control x:Name="Proxy" Background="White" /> 

And use in Pathbinding like this:

并在这样的Path绑定中使用:

<Path x:Name="path1" Fill="{Binding Path=Background, ElementName=Proxy}" Data="..." />

When you're in the Trigger set the color for the Proxy, his tucked up all the Path's.

当您在 Trigger 中为 Proxy 设置颜色时,他将所有路径都卷起来了。

Or instead of the binding Proxy, you can use any existing controls, such TextBlock.

或者代替绑定代理,您可以使用任何现有控件,例如TextBlock.

Full example:

完整示例:

<ControlTemplate x:Key="buttonTemplate" TargetType="{x:Type Button}">
    <Border x:Name="buttonBorder">
        <Grid>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="Auto"/>
                <ColumnDefinition Width="Auto"/>
            </Grid.ColumnDefinitions>

            <TextBlock x:Name="txtLabel" Grid.Column="0">                        
                <ContentPresenter />
            </TextBlock>

            <Control x:Name="Proxy" Background="White" /> 

            <Canvas x:Name="reschedule" Grid.Column="1">
                <Path x:Name="path1" Fill="{Binding Path=Background, ElementName=Proxy}" Data="..." />
                <Path x:Name="path2" Fill="{Binding Path=Background, ElementName=Proxy}" Data="..." />
            </Canvas>
        </Grid>
    </Border>

    <ControlTemplate.Triggers>
        <Trigger Property="IsMouseOver" Value="True">
            <Setter TargetName="buttonBorder" Property="Background" Value="DarkGreen" />
        </Trigger>

        <Trigger Property="IsEnabled" Value="False">
            <Setter TargetName="buttonBorder" Property="Background" Value="DarkGray" />
            <Setter TargetName="txtLabel" Property="Foreground" Value="Gray" />
            <Setter TargetName="Proxy" Property="Background" Value="Gray" />
        </Trigger>
    </ControlTemplate.Triggers>
</ControlTemplate>

回答by Heena Patil

1) Using Canvas Resourceto store path style.

1) 使用Canvas Resource存储路径样式。

Please see <Trigger Property="IsEnabled" Value="False">and <Trigger Property="IsEnabled" Value="True">

请看<Trigger Property="IsEnabled" Value="False"><Trigger Property="IsEnabled" Value="True">

 <Window.Resources>
    <ControlTemplate x:Key="buttonTemplate" TargetType="{x:Type Button}">
        <Border x:Name="buttonBorder">
            <Grid>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="Auto"/>
                    <ColumnDefinition Width="Auto"/>
                </Grid.ColumnDefinitions>
                <TextBlock x:Name="txtLabel" Grid.Column="0">
            <ContentPresenter/>
                </TextBlock>                                       
                <Canvas x:Name="reschedule" Grid.Column="1">
                    <Path x:Name="path1" Data="M 0 0 L 0 10 L 10 10 Z"/>
                    <Path x:Name="path2"  Data="M 0 0 L 0 10 L 10 10 Z" />                     
                </Canvas>
            </Grid>
        </Border>
        <ControlTemplate.Triggers>                                            
            <Trigger Property="IsEnabled" Value="False">
                <Setter TargetName="buttonBorder" Property="Background" Value="DarkGray"/>
                <Setter TargetName="reschedule" Property="Style">
                    <Setter.Value>
                        <Style TargetType="{x:Type Canvas}">
                            <Style.Resources>
                                <Style TargetType="{x:Type Path}">
                                    <Setter Property="Fill" Value="Green"></Setter>
                                </Style>
                            </Style.Resources>
                        </Style>
                    </Setter.Value>
                </Setter>
            </Trigger>                                       
            <Trigger Property="IsEnabled" Value="True">                 
                <Setter TargetName="reschedule" Property="Style">
                    <Setter.Value>
                        <Style TargetType="{x:Type Canvas}">
                            <Style.Resources>
                                <Style TargetType="{x:Type Path}">
                                    <Setter Property="Fill" Value="Blue"></Setter>
                                </Style>
                            </Style.Resources>
                        </Style>
                    </Setter.Value>
                </Setter>
            </Trigger>
        </ControlTemplate.Triggers>
    </ControlTemplate>       
</Window.Resources>

<StackPanel>
    <Button Height="40" Width="40" Template="{StaticResource buttonTemplate}" IsEnabled="False"></Button>
    <Button Height="40" Width="40" Margin="10" Template="{StaticResource buttonTemplate}" IsEnabled="True"></Button>
</StackPanel>

2) Using Canvas Tag

2) 使用Canvas 标签

  <Window.Resources>
    <ControlTemplate x:Key="buttonTemplate" TargetType="{x:Type Button}">
        <Border x:Name="buttonBorder">
            <Grid>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="Auto"/>
                    <ColumnDefinition Width="Auto"/>
                </Grid.ColumnDefinitions>
                <TextBlock x:Name="txtLabel" Grid.Column="0">
            <ContentPresenter/>
                </TextBlock>
                <Canvas x:Name="reschedule" Tag="Red" Grid.Column="1">
                    <Path x:Name="path1" Fill="{Binding Path=Tag,RelativeSource={RelativeSource AncestorType={x:Type Canvas}}}" Data="M 0 0 L 0 10 L 10 10 Z"/>
                    <Path x:Name="path2" Fill="{Binding Path=Tag,RelativeSource={RelativeSource AncestorType={x:Type Canvas}}}"  Data="M 0 0 L 0 10 L 10 10 Z" />
                </Canvas>
            </Grid>
        </Border>
        <ControlTemplate.Triggers>
            <Trigger Property="IsMouseOver" Value="True">
                <Setter TargetName="buttonBorder" Property="Background" Value="DarkGreen"/>
            </Trigger>
            <Trigger Property="IsEnabled" Value="False">
                <Setter TargetName="buttonBorder" Property="Background" Value="DarkGray"/>
                <Setter TargetName="reschedule" Property="Tag" Value="Green"/>
            </Trigger>
        </ControlTemplate.Triggers>
    </ControlTemplate>
</Window.Resources>

<StackPanel>
    <Button Height="40" Width="40" Template="{StaticResource buttonTemplate}" IsEnabled="False"></Button>
    <Button Height="40" Width="40" Margin="10" Template="{StaticResource buttonTemplate}" IsEnabled="True"></Button>
</StackPanel>

回答by XAMlMAX

Reason why your style wasn't working is because it was inside of the template.
To get it to work you need to apply your Style outside of your template. Not sure why it's done this way, might be something to do with how styles are processed in xaml.
Another matter to discuss is the significance of style definition:
<Style TargetType="Path">will not be the same as the <Style TargetType="{x:Type Path}">.
The first one will give you an error if defined in the resources tag, as it will need a key by which you can reference the style explicitly in all your target types.
The latter is assigned to every control of type Path, so if you define it inside DockPanelthen every Pathinside of that DockPanelwill be affected by the style, however if the Pathis outside of the DockPanelno styling will be applied, unless explicitly defined elsewhere, this style is applied to controls implicitly.
HTH

您的样式不起作用的原因是它在模板内。
要使其工作,您需要在模板之外应用您的样式。不知道为什么这样做,可能与 xaml 中的样式处理方式有关。
另一个要讨论的问题是样式定义的重要性:
<Style TargetType="Path">将与<Style TargetType="{x:Type Path}">.
如果在资源标签中定义,第一个会给你一个错误,因为它需要一个键,你可以通过它在所有目标类型中显式引用样式。
后者被分配给 type 的每个控件Path,所以如果你在里面定义它,那么它的DockPanel每个Path内部DockPanel都会受到样式的影响,但是如果PathDockPanel不会应用任何样式,除非在其他地方明确定义,否则此样式会隐式应用于控件。
HTH