问题
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 Path
s 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