locked
VisualState for ToggleButton RRS feed

  • Question

  • I am using the VisualStateManager and VisualSate and Storyboard to change the appearance of a toggle button.

    This works great for the Pressed, MouseOver, Checked and Unchecked States.  But I would like to enable a visible flag for a layer based on whether the IsChecked property of the togglebutton is true or false.  

    The toggle button is the PLAY button for a player.  I want to have a triangle image displayed for pressed and mouseover states then IsChecked is true and the dual vertical lines image (pause) when IsChecked is false.   How would I do this given the code below?

    <VisualStateManager.VisualStateGroups>
    	<VisualStateGroup x:Name="CommonStates">
    		<VisualState x:Name="Normal"/>
    		<VisualState x:Name="MouseOver">
    			<Storyboard>
    				<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Visibility)" Storyboard.TargetName="bt_Play_ON">
    					<DiscreteObjectKeyFrame KeyTime="0" Value="{x:Static Visibility.Visible}"/>
    				</ObjectAnimationUsingKeyFrames>
    			</Storyboard>
    		</VisualState>
    		<VisualState x:Name="Pressed">
    			<Storyboard>
    				<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Visibility)" Storyboard.TargetName="bt_Play_NORMAL_DOWN">
    					<DiscreteObjectKeyFrame KeyTime="0" Value="{x:Static Visibility.Visible}"/>
    				</ObjectAnimationUsingKeyFrames>
    			</Storyboard>
    		</VisualState>
    		<VisualState x:Name="Disabled"/>
    	</VisualStateGroup>
    	<VisualStateGroup x:Name="FocusStates"/>
    	<VisualStateGroup x:Name="CheckStates">
    		<VisualState x:Name="Checked">
    			<Storyboard>
    				<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Visibility)" Storyboard.TargetName="bt_Pause_NORMAL">
    					<DiscreteObjectKeyFrame KeyTime="0" Value="{x:Static Visibility.Visible}"/>
    				</ObjectAnimationUsingKeyFrames>
    				<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Visibility)" Storyboard.TargetName="bt_Play_NORMAL">
    					<DiscreteObjectKeyFrame KeyTime="0" Value="{x:Static Visibility.Hidden}"/>
    				</ObjectAnimationUsingKeyFrames>
    			</Storyboard>
    		</VisualState>
    		<VisualState x:Name="Unchecked">
    			<Storyboard>
    				<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Visibility)" Storyboard.TargetName="bt_Play_NORMAL">
    					<DiscreteObjectKeyFrame KeyTime="0" Value="{x:Static Visibility.Visible}"/>
    				</ObjectAnimationUsingKeyFrames>
    				<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Visibility)" Storyboard.TargetName="bt_Pause_NORMAL">
    					<DiscreteObjectKeyFrame KeyTime="0" Value="{x:Static Visibility.Hidden}"/>
    				</ObjectAnimationUsingKeyFrames>
    			</Storyboard>
    		</VisualState>
    		<VisualState x:Name="Indeterminate"/>
    	</VisualStateGroup>
    	<VisualStateGroup x:Name="ValidationStates"/>
    </VisualStateManager.VisualStateGroups>
    



    Jeff Davis

    Tuesday, June 11, 2013 11:09 PM

Answers

  • I did something a little less complicated to solve this....

    I juste used Multitrigger Conditions.  I test for the MouseOver or Pressed State and then test for IsChecked for the togglebutton.  Then I just set the visibility of the image I want.  Works pretty well.

    <ControlTemplate.Triggers>
    	<MultiTrigger>
    		<MultiTrigger.Conditions>
    			<Condition Property="IsMouseOver" Value="True"/>
    			<Condition Property="IsChecked" Value="True"/>
    		</MultiTrigger.Conditions>
    		<Setter TargetName="bt_Pause_ON" Property="Visibility" Value="Visible" />
    	</MultiTrigger>
    	<MultiTrigger>
    		<MultiTrigger.Conditions>
    			<Condition Property="IsMouseOver" Value="True"/>
    			<Condition Property="IsChecked" Value="False"/>
    		</MultiTrigger.Conditions>
    		<Setter TargetName="bt_Play_ON" Property="Visibility" Value="Visible" />
    	</MultiTrigger>						
    	<MultiTrigger>
    		<MultiTrigger.Conditions>
    			<Condition Property="IsPressed" Value="True"/>
    			<Condition Property="IsChecked" Value="False"/>
    		</MultiTrigger.Conditions>
    		<Setter TargetName="bt_Play_NORMAL_DOWN" Property="Visibility" Value="Visible" />
    	</MultiTrigger>						
    	<MultiTrigger>
    		<MultiTrigger.Conditions>
    			<Condition Property="IsPressed" Value="True"/>
    			<Condition Property="IsChecked" Value="True"/>
    		</MultiTrigger.Conditions>
    		<Setter TargetName="bt_Pause_NORMAL_DOWN" Property="Visibility" Value="Visible" />
    	</MultiTrigger>						
    </ControlTemplate.Triggers>


    Jeff Davis

    • Marked as answer by JeffD503 Monday, June 17, 2013 8:18 PM
    Monday, June 17, 2013 8:18 PM

All replies

  • Hello Jeff.

    You could just use triggers in your ToggleButtonStyle.

    <Window
    	xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    	xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    	xmlns:Microsoft_Windows_Themes="clr-namespace:Microsoft.Windows.Themes;assembly=PresentationFramework.Aero" 
    	xmlns:ed="http://schemas.microsoft.com/expression/2010/drawing"
    	x:Class="WpfApplication31.MainWindow"
    	x:Name="Window"
    	Title="MainWindow"
    	Width="640" Height="480">
    
    	<Window.Resources>
    		<Style x:Key="ButtonFocusVisual">
    			<Setter Property="Control.Template">
    				<Setter.Value>
    					<ControlTemplate>
    						<Rectangle Margin="2" SnapsToDevicePixels="true" Stroke="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}" StrokeThickness="1" StrokeDashArray="1 2"/>
    					</ControlTemplate>
    				</Setter.Value>
    			</Setter>
    		</Style>
    		<LinearGradientBrush x:Key="ButtonNormalBackground" EndPoint="0,1" StartPoint="0,0">
    			<GradientStop Color="#F3F3F3" Offset="0"/>
    			<GradientStop Color="#EBEBEB" Offset="0.5"/>
    			<GradientStop Color="#DDDDDD" Offset="0.5"/>
    			<GradientStop Color="#CDCDCD" Offset="1"/>
    		</LinearGradientBrush>
    		<SolidColorBrush x:Key="ButtonNormalBorder" Color="#FF707070"/>
    		<Style x:Key="ToggleButtonStyle1" TargetType="{x:Type ToggleButton}">
    			<Setter Property="FocusVisualStyle" Value="{StaticResource ButtonFocusVisual}"/>
    			<Setter Property="Background" Value="{StaticResource ButtonNormalBackground}"/>
    			<Setter Property="BorderBrush" Value="{StaticResource ButtonNormalBorder}"/>
    			<Setter Property="BorderThickness" Value="1"/>
    			<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
    			<Setter Property="HorizontalContentAlignment" Value="Center"/>
    			<Setter Property="VerticalContentAlignment" Value="Center"/>
    			<Setter Property="Padding" Value="1"/>
    			<Setter Property="Template">
    				<Setter.Value>
    					<ControlTemplate TargetType="{x:Type ToggleButton}">
    						<ControlTemplate.Resources>
    							<Storyboard x:Key="Storyboard1">
    								<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Visibility)" Storyboard.TargetName="play">
    									<DiscreteObjectKeyFrame KeyTime="0" Value="{x:Static Visibility.Collapsed}"/>
    								</ObjectAnimationUsingKeyFrames>
    								<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Visibility)" Storyboard.TargetName="pause">
    									<DiscreteObjectKeyFrame KeyTime="0" Value="{x:Static Visibility.Visible}"/>
    								</ObjectAnimationUsingKeyFrames>
    							</Storyboard>
    							<Storyboard x:Key="Storyboard2">
    								<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Visibility)" Storyboard.TargetName="play">
    									<DiscreteObjectKeyFrame KeyTime="0" Value="{x:Static Visibility.Visible}"/>
    								</ObjectAnimationUsingKeyFrames>
    								<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Visibility)" Storyboard.TargetName="pause">
    									<DiscreteObjectKeyFrame KeyTime="0" Value="{x:Static Visibility.Collapsed}"/>
    								</ObjectAnimationUsingKeyFrames>
    							</Storyboard>
    						</ControlTemplate.Resources>
    						<Microsoft_Windows_Themes:ButtonChrome x:Name="Chrome" BorderBrush="{TemplateBinding BorderBrush}" Background="{TemplateBinding Background}" RenderMouseOver="{TemplateBinding IsMouseOver}" RenderPressed="{TemplateBinding IsPressed}" RenderDefaulted="{TemplateBinding Button.IsDefaulted}" SnapsToDevicePixels="true">
    							<Grid Height="100" Width="100">
    								<ed:RegularPolygon x:Name="play" Fill="Gray" Height="Auto" InnerRadius="1" PointCount="3" Stretch="Fill" Stroke="Black" Width="Auto" RenderTransformOrigin="0.5,0.5" Margin="10">
    									<ed:RegularPolygon.RenderTransform>
    										<TransformGroup>
    											<ScaleTransform/>
    											<SkewTransform/>
    											<RotateTransform Angle="90"/>
    											<TranslateTransform/>
    										</TransformGroup>
    									</ed:RegularPolygon.RenderTransform>
    								</ed:RegularPolygon>
    								<Grid x:Name="pause" Margin="10" Visibility="Hidden">
    									<Grid.ColumnDefinitions>
    										<ColumnDefinition Width="2*"/>
    										<ColumnDefinition Width="1*"/>
    										<ColumnDefinition Width="2*"/>
    									</Grid.ColumnDefinitions>
    									<Rectangle Fill="Gray" Stroke="Black" HorizontalAlignment="Stretch"/>
    									<Rectangle Fill="Gray" Stroke="Black" HorizontalAlignment="Stretch" Grid.Column="2"/>
    								</Grid>
    							</Grid>
    						</Microsoft_Windows_Themes:ButtonChrome>
    						<ControlTemplate.Triggers>
    							<Trigger Property="IsChecked" Value="True">
    								<Trigger.ExitActions>
    									<BeginStoryboard x:Name="Storyboard2_BeginStoryboard2" Storyboard="{StaticResource Storyboard2}"/>
    								</Trigger.ExitActions>
    								<Trigger.EnterActions>
    									<BeginStoryboard x:Name="Storyboard2_BeginStoryboard" Storyboard="{StaticResource Storyboard1}"/>
    								</Trigger.EnterActions>
    							</Trigger>
    							<Trigger Property="IsKeyboardFocused" Value="true">
    								<Setter Property="RenderDefaulted" TargetName="Chrome" Value="true"/>
    							</Trigger>
    							<Trigger Property="IsEnabled" Value="false">
    								<Setter Property="Foreground" Value="#ADADAD"/>
    							</Trigger>
    						</ControlTemplate.Triggers>
    					</ControlTemplate>
    				</Setter.Value>
    			</Setter>
    		</Style>
    	</Window.Resources>
    
    	<Grid x:Name="LayoutRoot">
    		<ToggleButton Content="ToggleButton" HorizontalAlignment="Center" VerticalAlignment="Center" Style="{DynamicResource ToggleButtonStyle1}"/>
    	</Grid>
    </Window>

    With your template open, Right-Click, Edit Template > Edit Current or a Copy.

    Replace the ContentPresenter with something like this bit here...

    <Grid Height="100" Width="100">
    	<ed:RegularPolygon x:Name="play" Fill="Gray" Height="Auto" InnerRadius="1" PointCount="3" Stretch="Fill" Stroke="Black" Width="Auto" RenderTransformOrigin="0.5,0.5" Margin="10">
    		<ed:RegularPolygon.RenderTransform>
    			<TransformGroup>
    				<ScaleTransform/>
    				<SkewTransform/>
    				<RotateTransform Angle="90"/>
    				<TranslateTransform/>
    			</TransformGroup>
    		</ed:RegularPolygon.RenderTransform>
    	</ed:RegularPolygon>
    	<Grid x:Name="pause" Margin="10" Visibility="Hidden">
    		<Grid.ColumnDefinitions>
    			<ColumnDefinition Width="2*"/>
    			<ColumnDefinition Width="1*"/>
    			<ColumnDefinition Width="2*"/>
    		</Grid.ColumnDefinitions>
    		<Rectangle Fill="Gray" Stroke="Black" HorizontalAlignment="Stretch"/>
    		<Rectangle Fill="Gray" Stroke="Black" HorizontalAlignment="Stretch" Grid.Column="2"/>
    	</Grid>
    </Grid>

    Then go to the Triggers Panel > Add a Property Trigger.

    Set it up so that when "IsChecked" is true it activates Storyboard1 and uses Storyboard2 when deactivating.

    Hopefully that will gie you some ideas.

    ~Christine


    Thursday, June 13, 2013 3:44 AM
  • I did something a little less complicated to solve this....

    I juste used Multitrigger Conditions.  I test for the MouseOver or Pressed State and then test for IsChecked for the togglebutton.  Then I just set the visibility of the image I want.  Works pretty well.

    <ControlTemplate.Triggers>
    	<MultiTrigger>
    		<MultiTrigger.Conditions>
    			<Condition Property="IsMouseOver" Value="True"/>
    			<Condition Property="IsChecked" Value="True"/>
    		</MultiTrigger.Conditions>
    		<Setter TargetName="bt_Pause_ON" Property="Visibility" Value="Visible" />
    	</MultiTrigger>
    	<MultiTrigger>
    		<MultiTrigger.Conditions>
    			<Condition Property="IsMouseOver" Value="True"/>
    			<Condition Property="IsChecked" Value="False"/>
    		</MultiTrigger.Conditions>
    		<Setter TargetName="bt_Play_ON" Property="Visibility" Value="Visible" />
    	</MultiTrigger>						
    	<MultiTrigger>
    		<MultiTrigger.Conditions>
    			<Condition Property="IsPressed" Value="True"/>
    			<Condition Property="IsChecked" Value="False"/>
    		</MultiTrigger.Conditions>
    		<Setter TargetName="bt_Play_NORMAL_DOWN" Property="Visibility" Value="Visible" />
    	</MultiTrigger>						
    	<MultiTrigger>
    		<MultiTrigger.Conditions>
    			<Condition Property="IsPressed" Value="True"/>
    			<Condition Property="IsChecked" Value="True"/>
    		</MultiTrigger.Conditions>
    		<Setter TargetName="bt_Pause_NORMAL_DOWN" Property="Visibility" Value="Visible" />
    	</MultiTrigger>						
    </ControlTemplate.Triggers>


    Jeff Davis

    • Marked as answer by JeffD503 Monday, June 17, 2013 8:18 PM
    Monday, June 17, 2013 8:18 PM