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

╄→гoц情女王★ 提交于 2019-12-11 03:39:21

问题


I have the following ControlTemplate defined:

<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 TextBlock Foreground and Path Fill properties have been set to White. When the button is disabled I want to set those properties to Gray. Right now it works for the TextBlock and I can make it work for the Paths too by targetting each of their names, but is there a way to target all the Path elements by type? Something like:

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

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

<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>

回答1:


You can try this trick:

Create a proxy control for Binding:

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

And use in Path binding like this:

<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.

Or instead of the binding Proxy, you can use any existing controls, such 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>



回答2:


1) Using Canvas Resource to store path style.

Please see <Trigger Property="IsEnabled" Value="False"> and <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

  <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>



回答3:


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 DockPanel then every Path inside of that DockPanel will be affected by the style, however if the Path is outside of the DockPanel no styling will be applied, unless explicitly defined elsewhere, this style is applied to controls implicitly.
HTH



来源:https://stackoverflow.com/questions/28034009/wpf-is-there-a-way-to-target-an-element-type-in-a-controltemplates-trigger

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!