Reputation: 38209
I would like to change view of button after button is clicked.
For example, I have two templates beforeClicking
and afterClicking
:
<Style TargetType="Button">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button" x:Name="beforeClicking">
<Border Name="border" Background="Transparent" BorderThickness="1" BorderBrush="Black">
<ContentPresenter/>
</Border>
</ControlTemplate>
<!--It is not permitted, but that is pseudocode(what I want)
<ControlTemplate TargetType="Button" x:Name="afterClicking">
<Border Name="border" Background="Transparent" BorderThickness="10" BorderBrush="Black">
<ContentPresenter/>
</Border>
</ControlTemplate>
-->
</Setter.Value>
</Setter>
</Style>
What I want is when button is not clicked, then a template beforeClicking
should be permanently used and nothing(template or view) should not be altered.
However, if user clicks, then button should use
a template afterClicking
permanently and the view of button should not be altered.
That is at the first click the button uses template afterClicking
. At the second click the button uses template beforeClicking
. At the third click the button uses template afterClicking
. At the fourth click the button uses template afterClicking
. And so on.
I would like to get such behavior just by XAML since MVVM approach is used.
How to achieve such a behavior?
Upvotes: 1
Views: 1292
Reputation: 533
If I were you I would use System.Windows.Interactivity.Behavior
rather than EventTriggers
, unfortunately EventTriggers
are the only way for you to associate in xaml event with operation, the only problem is that EventTriggers
only work with TriggerAction
objects and you can't create your TriggerAction
. This because it is an abstract class which abstract methods are internal and not overridable from outside PresentationFramework library.
Here is an example of how prepare your Behavior class:
public class ChangeTemplateBehavior : System.Windows.Interactivity.Behavior<Button>
{
public static readonly DependencyProperty ControlTemplate1Property = DependencyProperty.Register("ControlTemplate1", typeof(ControlTemplate), typeof(ChangeTemplateBehavior), new PropertyMetadata(default(ControlTemplate)));
public ControlTemplate ControlTemplate1
{
get
{
return (ControlTemplate)GetValue(ControlTemplate1Property);
}
set
{
SetValue(ControlTemplate1Property, value);
}
}
public static readonly DependencyProperty ControlTemplate2Property = DependencyProperty.Register("ControlTemplate2", typeof(ControlTemplate), typeof(ChangeTemplateBehavior), new PropertyMetadata(default(ControlTemplate)));
public ControlTemplate ControlTemplate2
{
get
{
return (ControlTemplate)GetValue(ControlTemplate2Property);
}
set
{
SetValue(ControlTemplate2Property, value);
}
}
protected override void OnAttached()
{
base.OnAttached();
this.AssociatedObject.Click += AssociatedObject_Click;
}
void AssociatedObject_Click(object sender, RoutedEventArgs e)
{
if (this.AssociatedObject.Template == this.ControlTemplate2)
{
this.AssociatedObject.Template = this.ControlTemplate1;
}
else
{
this.AssociatedObject.Template = this.ControlTemplate2;
}
}
}
And here is an example of how to write your xaml code:
<Window x:Class="StackoverflowHelpWPF5.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:[YOURLOCALNAMESPACEHERE]"
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<ControlTemplate TargetType="Button" x:Key="beforeClicking">
<Border Name="border" Background="Transparent" BorderThickness="1" BorderBrush="Black">
<ContentPresenter/>
</Border>
</ControlTemplate>
<ControlTemplate TargetType="Button" x:Key="afterClicking">
<Border Name="border" Background="Transparent" BorderThickness="10" BorderBrush="Black">
<ContentPresenter/>
</Border>
</ControlTemplate>
</Window.Resources>
...
<Button Template="{StaticResource beforeClicking}" >
<i:Interaction.Behaviors>
<local:ChangeTemplateBehavior ControlTemplate1="{StaticResource afterClicking}" ControlTemplate2="{StaticResource beforeClicking}"></local:ChangeTemplateBehavior>
</i:Interaction.Behaviors>
</Button>
Upvotes: 1
Reputation: 2037
You can handle a click using an EventTrigger. In an event trigger you provide a Storyboard, but in a Storyboard you can't change the Template.
You could do this in an attached property, but looking at your example, you don't need to, and more typically, you'd affect individual properties:
<Style TargetType="Button">
<Setter Property="BorderThickness" Value="1" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Border Name="border" Background="Transparent" BorderThickness="{TemplateBinding BorderThickness}" BorderBrush="Black">
<ContentPresenter/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<EventTrigger RoutedEvent="Click">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard>
<ThicknessAnimationUsingKeyFrames Storyboard.TargetProperty="BorderThickness">
<DiscreteThicknessKeyFrame Value="10" KeyTime="0" />
</ThicknessAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
</Style.Triggers>
</Style>
==After discussion: ToggleButton version:==
<Window.Resources>
<Style TargetType="ToggleButton">
<Setter Property="BorderThickness" Value="1" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ToggleButton">
<Border Name="border" Background="Transparent" BorderThickness="{TemplateBinding BorderThickness}" BorderBrush="Black">
<ContentPresenter/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsChecked" Value="True">
<Setter Property="BorderThickness" Value="10" />
</Trigger>
</Style.Triggers>
</Style>
</Window.Resources>
<Grid>
<ToggleButton>Hello World</ToggleButton>
</Grid>
Upvotes: 1