WPF - 有没有办法在 ControlTemplate 的触发器中定位元素类型?
WPF - Is there a way to target an element type in a ControlTemplate's trigger?
我定义了以下 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>
目前默认的 TextBlock
Foreground
和 Path
Fill
属性已设置为 White
。当按钮被禁用时,我想将这些属性设置为 Gray
。现在它适用于 TextBlock
,我也可以通过定位它们的每个名称使其适用于 Path
,但是有没有一种方法可以按类型定位所有 Path
元素?类似于:
<Setter TargetType="Path" Property="Fill" Value="Gray"/>
我尝试将以下触发器添加到 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>
你可以试试这个技巧:
为 Binding
创建代理控件:
<Control x:Name="Proxy" Background="White" />
并像这样在 Path
绑定中使用:
<Path x:Name="path1" Fill="{Binding Path=Background, ElementName=Proxy}" Data="..." />
当您在触发器中时,为代理设置颜色,他隐藏了所有路径。
或者不使用绑定代理,您可以使用任何现有的控件,例如 TextBlock
。
完整示例:
<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>
1) 使用Canvas资源来存储路径样式。
请参阅 <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) 使用 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>
您的样式不起作用的原因是它在模板内部。
要让它工作,您需要在模板之外应用您的样式。不确定为什么这样做,可能与 xaml.
中样式的处理方式有关
另外要讨论的是样式定义的意义:
<Style TargetType="Path">
将与 <Style TargetType="{x:Type Path}">
不同。
如果在资源标记中定义第一个,则会给您一个错误,因为它需要一个键,您可以通过该键在所有目标类型中显式引用样式。
后者被分配给 Path
类型的每个控件,因此如果您在 DockPanel
中定义它,那么 DockPanel
中的每个 Path
都会受到样式的影响,但是如果Path
在 DockPanel
之外,不会应用任何样式,除非在其他地方明确定义,否则此样式将隐式应用于控件。
HTH
我定义了以下 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>
目前默认的 TextBlock
Foreground
和 Path
Fill
属性已设置为 White
。当按钮被禁用时,我想将这些属性设置为 Gray
。现在它适用于 TextBlock
,我也可以通过定位它们的每个名称使其适用于 Path
,但是有没有一种方法可以按类型定位所有 Path
元素?类似于:
<Setter TargetType="Path" Property="Fill" Value="Gray"/>
我尝试将以下触发器添加到 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>
你可以试试这个技巧:
为 Binding
创建代理控件:
<Control x:Name="Proxy" Background="White" />
并像这样在 Path
绑定中使用:
<Path x:Name="path1" Fill="{Binding Path=Background, ElementName=Proxy}" Data="..." />
当您在触发器中时,为代理设置颜色,他隐藏了所有路径。
或者不使用绑定代理,您可以使用任何现有的控件,例如 TextBlock
。
完整示例:
<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>
1) 使用Canvas资源来存储路径样式。
请参阅 <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) 使用 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>
您的样式不起作用的原因是它在模板内部。
要让它工作,您需要在模板之外应用您的样式。不确定为什么这样做,可能与 xaml.
中样式的处理方式有关
另外要讨论的是样式定义的意义:
<Style TargetType="Path">
将与 <Style TargetType="{x:Type Path}">
不同。
如果在资源标记中定义第一个,则会给您一个错误,因为它需要一个键,您可以通过该键在所有目标类型中显式引用样式。
后者被分配给 Path
类型的每个控件,因此如果您在 DockPanel
中定义它,那么 DockPanel
中的每个 Path
都会受到样式的影响,但是如果Path
在 DockPanel
之外,不会应用任何样式,除非在其他地方明确定义,否则此样式将隐式应用于控件。
HTH