How to reference the parent control from a style ControlTemplate in WPF?
I have a simple style for label controls. I'd like to define a control template inside the style with a button, which could be clicked and would set the visibility property of the label to 'Hidden'. Something like this:
<Style x:Key="MessageLabel_WithCloseButton" TargetType="{x:Type Label}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Label}">
<Border BorderThickness="1" Padding="4" CornerRadius="3"
BorderBrush="Gray" Background="#FFA11616">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<ContentPresenter Grid.Column="0"/>
<Button Grid.Column="1" Width="16" Height="16" Padding="2" FontSize="9" Content="X">
<!-- THIS IS WRONG! HOW TO CREATE A TRIGGER FOR THIS BUTTON
HERE AND HOW TO REFER TO THE LABEL? -->
<Button.Triggers>
开发者_如何学Go <Trigger Property="Button.IsPressed" Value="True">
<Setter Property="Visibility" Value="Hidden" />
</Trigger>
</Button.Triggers>
</Button>
</Grid>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
The problem is I'm not sure how to handle the click with a trigger and also how to set a property of the label that contains the button.
Thanks.
I authored this with Blend 4. Essentially you want to handle the "PreviewMouseButtonUp" event on your button with an EventTrigger
. The EventTrigger
will start a Storyboard
which animates the UIElement.Visibility property to "Hidden" at the top of the Visual Tree for your label's style.
To get control over the content in the button, you can use the Tag
Property on the label control. Otherwise, you will have to create another dependency property, and that means subclassing Label
.
Inside the style, then, the <Button/>
looks like this:
<Button x:Name="button" Grid.Column="1" Padding="2"
FontSize="9"
Content="{Binding Path=Tag, RelativeSource={RelativeSource TemplatedParent}}"/>
...and since you can put anything into a Tag
property you can do this:
<Label x:Name="label" Content="Label"
Style="{DynamicResource MessageLabel_WithCloseButton}">
<Label.Tag>
<StackPanel>
<TextBlock>WOOT</TextBlock>
<TextBlock>WOOT</TextBlock>
</StackPanel>
</Label.Tag>
</Label>
Here is a modified complete style (I also modified some things for better automatic sizing:
<Style x:Key="MessageLabel_WithCloseButton" TargetType="{x:Type Label}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Label}">
<ControlTemplate.Resources>
<Storyboard x:Key="OnClick1">
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Visibility)" Storyboard.TargetName="border">
<DiscreteObjectKeyFrame KeyTime="0">
<DiscreteObjectKeyFrame.Value>
<Visibility>Hidden</Visibility>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</ControlTemplate.Resources>
<Border x:Name="border" BorderThickness="1" Padding="4" CornerRadius="3"
BorderBrush="Gray" Background="#FFA11616">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<ContentPresenter Grid.Column="0" VerticalAlignment="Center" Margin="0,0,3,0"/>
<Button x:Name="button" Grid.Column="1" Padding="2" FontSize="9" Content="{Binding Path=Tag, RelativeSource={RelativeSource TemplatedParent}}"/>
</Grid>
</Border>
<ControlTemplate.Triggers>
<EventTrigger RoutedEvent="UIElement.PreviewMouseLeftButtonUp" SourceName="button">
<BeginStoryboard x:Name="OnClick1_BeginStoryboard" Storyboard="{StaticResource OnClick1}"/>
</EventTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Note, too, that the EventTrigger
is on your ControlTemplate
and not on the Button
in your tree. But that might be just the way Blend generates the code.
You can use a ToggleButton instead of the normal Button and then just use the IsChecked property for the Trigger:
<Style x:Key="MessageLabel_WithCloseButton" TargetType="{x:Type Label}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Label}">
<Border BorderThickness="1" Padding="4" CornerRadius="3"
BorderBrush="Gray" Background="#FFA11616">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<ContentPresenter Grid.Column="0"/>
<ToggleButton x:Name="CloseButton" Grid.Column="1" Width="16" Height="16" Padding="2" FontSize="9" Content="X"/>
</Grid>
</Border>
<ControlTemplate.Triggers>
<Trigger SourceName="CloseButton" Property="IsChecked" Value="True">
<Setter Property="Visibility" Value="Hidden" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
精彩评论