Setting Grid width = "*" in Visual State Manager in Xaml - wpf

I am trying to build a UWP app that uses a Hub component to display 2 HubSections when in wide mode (default) and then to switch to showing only one HubSection when in Narrow mode
My HubSection is defined as follows:
<Hub>
<HubSection x:Name="Column1" Header="section 1" Background="Cornsilk">
</HubSection>
<HubSection x:Name="Column2" Header="section 2" Background="Chocolate">
</HubSection>
</Hub>
My Visual State Manager is defined like this:
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="AdaptiveStates">
<VisualState x:Name="DefaultState">
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="720" />
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Target="Column1.Width" Value="500" />
<Setter Target="Column2.Width" Value="700" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="NarrowState">
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="0" />
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Target="Column1.Width" Value="*" /> <--- This line doesn't work as * is not a number
<Setter Target="Column2.Width" Value="0" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
The Question is how do I set the width of a component to * or "Use all space available" in the Visual State Manager?

Not sure for HubControl, but I've done the same with a normal Grid ( to hide a column ).
Source here: https://github.com/AppCreativity/Kliva/blob/master/src/Kliva/Views/MainPage.xaml#L75
I needed to give the columndefinitions a name and use those in the visual state manager

Related

How to disable the Hamburger Menu for certain views in WPF?

I have a login page that I want to show upon App launch within my Main Window that has a Hamburger Menu in the left side. How can I hide/disable this?
This is a desktop application created by using WPF along with MahApps.Metro library.
Depending on the Window size, either a larger menu should be shown on top, or the Hamburger button with the menus in the SplitView pane. This functionality is offered by the adaptive trigger. The following code snippet changes the visibility of the horizontal menu and the Hamburger button depending on Window sizes 320 and 720.
<VisualStateManager.VisualStateGroups>
<VisualStateGroup>
<VisualState x:Name="MediumState">
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="720" />
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Target="HorizontalMenu.Visibility" Value="Visible" />
<Setter Target="HamburgerButton.Visibility" Value="Collapsed" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="XSmallState">
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="320" />
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Target="HamburgerButton.Visibility" Value="Visible" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
Typical triggers for the Window sizes are 320, 548, 720, and 1024.
The menu for the larger Window is just defined within a StackPanel:
<StackPanel x:DeferLoadStrategy="Lazy" x:Name="HorizontalMenu" Orientation="Horizontal" Visibility="Collapsed">
<Button Content="One" Style="{StaticResource MenuButtonStyle}" />
<Button Content="Two" Style="{StaticResource MenuButtonStyle}" />
</StackPanel>

Best way to "group" items "virtually"?

I'm working on a custom items based WPF control. For the "normal" layout, think vertical StackPanel, so my xaml would look something like:
<mycontrol>
<item1 />
<item2 />
<item3 />
</mycontrol>
In this case, its simple, 3 item containers are created and all is good. The control will look like:
[item1]
[item2]
[item3]
Use case #2 is, I need to support horizontal "grouping"... ideally my xaml would look like:
<mycontrol>
<item1 />
<stackpanel orientation=horizontal>
<item2a />
<item2b />
<item2c />
</stackpanel>
<item3 />
</mycontrol>
and in this case, I would render as:
[item1]
[item2a] [item2b] [item2c]
[item3]
So, what I'm going for is 5 item containers being generated. I've already worked out a custom layout panel and that part works.
The issue is, if I use a stackpanel, I'll only get 3 item containers which makes sense, duh, but it breaks the keyboard interface of the control. I could do something hacky where I intercept all the keyboard and mouse stuff and "re-route" it in this case, but that seems hacky and difficult to get to work in a generic way.
Is there something obscure built into WPF to deal with this? The "sub items" getting generated as thier own containers?
The way I'm currently heading is to do something like:
<item1 />
<item2a isGrouped=true />
<item2b isGrouped=true />
<item2c isGrouped=true />
<item3 />
So, when I hit the first isGrouped=true, it'll start grouping until it hits a false, but I'm not crazy about that either because I'll have to make isGrouped a 3 state enum so I can have one group right below another group. Also, the hierarchy is not clear in the xaml.
Any suggestions?
I was able to get more or less the look you are going for using a HierarchicalDataTemplate within a TreeView that uses a custom TreeViewItem control template. For the control template, I simply copied the example template and made a few modifications. All of the containers are in the right place, but the keyboard navigation doesn't work on the nested items (because TreeView is not expecting that layout I guess). Here is what I came up with:
<TreeView
ItemsSource="{Binding Items}">
<TreeView.Resources>
<Color x:Key="SelectedBackgroundColor">#FFC5CBF9</Color>
<Color x:Key="SelectedUnfocusedColor">#FFDDDDDD</Color>
<Style
TargetType="{x:Type TreeViewItem}">
<Setter
Property="ItemsPanel">
<Setter.Value>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</Setter.Value>
</Setter>
<Setter
Property="IsExpanded"
Value="True" />
<Setter
Property="Template">
<Setter.Value>
<!-- This template came from the example template and has just a few modifications.
Example is at: https://msdn.microsoft.com/en-us/library/ms752048.aspx -->
<ControlTemplate
TargetType="{x:Type TreeViewItem}">
<Grid>
<!-- Changed the grid configuration -->
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<!-- The entire VisualStateGroups section is a direct copy+paste from the example template -->
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="SelectionStates">
<VisualState x:Name="Selected">
<Storyboard>
<ColorAnimationUsingKeyFrames
Storyboard.TargetName="Bd"
Storyboard.TargetProperty="(Panel.Background).(SolidColorBrush.Color)">
<EasingColorKeyFrame
KeyTime="0"
Value="{StaticResource SelectedBackgroundColor}" />
</ColorAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="Unselected" />
<VisualState x:Name="SelectedInactive">
<Storyboard>
<ColorAnimationUsingKeyFrames
Storyboard.TargetName="Bd"
Storyboard.TargetProperty="(Panel.Background).(SolidColorBrush.Color)">
<EasingColorKeyFrame
KeyTime="0"
Value="{StaticResource SelectedUnfocusedColor}" />
</ColorAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
</VisualStateGroup>
<VisualStateGroup x:Name="ExpansionStates">
<VisualState x:Name="Expanded">
<Storyboard>
<ObjectAnimationUsingKeyFrames
Storyboard.TargetProperty="(UIElement.Visibility)"
Storyboard.TargetName="ItemsHost">
<DiscreteObjectKeyFrame
KeyTime="0"
Value="{x:Static Visibility.Visible}" />
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="Collapsed" />
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<!-- Removed the ToggleButton -->
<!-- Tweaked the placement of items in the grid -->
<Border
x:Name="Bd"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Padding="{TemplateBinding Padding}">
<ContentPresenter
x:Name="PART_Header"
ContentSource="Header"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"/>
</Border>
<ItemsPresenter
x:Name="ItemsHost"
Grid.Column="1" />
</Grid>
<ControlTemplate.Triggers>
<!-- Removed the IsExpanded trigger -->
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="HasHeader" Value="false" />
<Condition Property="Width" Value="Auto" />
</MultiTrigger.Conditions>
<Setter
TargetName="PART_Header"
Property="MinWidth"
Value="75" />
</MultiTrigger>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="HasHeader" Value="false" />
<Condition Property="Height" Value="Auto" />
</MultiTrigger.Conditions>
<Setter
TargetName="PART_Header"
Property="MinHeight"
Value="19" />
</MultiTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</TreeView.Resources>
<TreeView.ItemTemplate>
<HierarchicalDataTemplate
DataType="{x:Type local:MyItem}"
ItemsSource="{Binding Children}">
<TextBlock Text="{Binding Name}" />
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
For reference, my ItemsSource property is bound to a collection containing items that look like this:
internal class MyItem
{
public string Name { get; private set; }
public List<MyItem> Children { get; private set; }
public MyItem(string name = null)
{
Name = name;
Children = new List<MyItem>();
}
}
This is done without creating a custom control, but hopefully it gives you an idea of what you can do. The combination of a HeirarchicalDataTemplate and a specialized container type (in my case TreeViewItem with a custom control template) is key to the way I did it.
Here is some data that I tested with and the result:
public IEnumerable<MyItem> Items { get; private set; }
...
var items = new MyItem[]
{
new MyItem("[First]"),
new MyItem(),
new MyItem("[Third]")
};
items[1].Children.Add(new MyItem("[Second_0]"));
items[1].Children.Add(new MyItem("[Second_1]"));
items[1].Children.Add(new MyItem("[Second_2]"));
Items = items;
I am sure the visualization could be improved. I just threw this together in under 10 minutes.

In XAML, What is the correct XML namespace for VisualStateManager?

I'm trying to restyle a few ToggleButtons. Apparently I cannot simply set the background to a new color, because there is a "Control Template" that provides the ToggleButton's visual behavior.
So what I need to do is specify in XAML a replacement "ControlTemplate" for the ToggleButton that provides different visual behavior, beyond the simple background color.
Q1. Is this correct?
I figured to start with the "default" controltemplate for the ToggleButton, which I grabbed from here, and then modify it. Actually that is the default ControlTemplate for Silverlight, I guess, and I am not using Silverlight, I'm using WPF. But... The corresponding doc page for WPF does not include a specification of the default controltemplate. It provides "a" ControlTemplate, which is not what I want.
Q2. I'm not sure if it matters that I am using the thing from Silverlight. Does it?
In the Silverlight example, there is an XML namespace prefix of of vsm applied to the VisualStateManager. Apparently the xml namespace is
xmlns:vsm = "clr-namespace:System.Windows;assembly=System.Windows"
... but somewhere else I read that this XML namespace "is no longer necessary."
This is all very very confusing.
In the Googlespace, there are references to something called "The WPF toolkit" which I have had prior exposure to - I used it for an autocomplete textbox prior to the release of WPF V4. I am guessing that some of the WPF Toolkit stuff was rolled into WPF for .NET v4.0, and that is why I no longer have to specify the WPF toolkit.
Q3. If someone could confirm that understanding I'd appreciate it.
Ok, now starting with the "default" ControlTemplate for ToggleButton, my first step was to compile it, before making any changes. It does not compile, failing with
c:\dev...\ToggleButtonStyle1.xaml(23,14): error MC3074: The tag 'VisualStateManager.VisualStateGroups' does not exist in XML namespace 'http://schemas.microsoft.com/winfx/2006/xaml/presentation'. Line 23 Position 14.
Clear enough. I then
looked at the documentation for specifying VisualStateManager in XAML. It, confusingly enough, specifies two xml namespaces, one of them is the one I actually used.
Q4 Um, which of these am I supposed to use? One of them, I DID use, and it didn't work. The documentation is completely unclear on what it means to specify TWO XML namespaces. (off with their heads!)
I have a reference to PresentationFramework.dll in the project file:
<ItemGroup>
....
<Reference Include="PresentationFramework" />
</ItemGroup>
I am not using Visual Studio here; I'm using a text editor. I want to understand how it works, not what buttons to push.
Thanks for any help y'all can provide.
Just a side comment - this all seems very very complicated. All I want to do is change the color of a ToggleButton when it is ON. It really shouldn't be this complicated.
You don't need to specify a namespace for the VSM (the http://schemas.microsoft.com/winfx/2006/xaml/presentation namespace is the default WPF namespace, declared as xmlns="..." in most standard .xaml's) -- you can however only use it at certain parts of your visual hierarchy.
For example, when I use the VSM in a standard UserControl, it looks something like so:
<UserControl x:Class="Whatever"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid x:Name="LayoutRoot">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Disabled">
<!-- Storyboards go here -->
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</Grid>
</UserControl>
Placing the VSM xaml at this level will enable your storyboards to refer to any elements contained within the Grid. This works the same in a ControlTemplate like you're working with. One thing to note though, is that while in your own UserControls you can name the visual states whatever you like (because you'll ultimately be making calls to switch to that visual state in code), with the built-in controls, your visual states have to be named exactly what the control is expecting.
Answering my own question....
Q1 YES
Q2 No - it doesn't matter. The templates are "about" the same.
Q3 Not sure
Q4 I don't know.
The key here was that I needed to specify TargetFramework = 4.0. I had been compiling against v3.5, and the VSM I guess was first available in v4.0, so that was the reason for the "not found in namespace xxxxx" error.
I did not need to specify an XMLNS in the XAML file.
Stepping back - the answer to the larger question - how to get a ToggleButton that changes color when depressed... I tried fiddling with the builtin ControlTemplate, but it was too complicated for me to understand. The animations that occurred with the Press and Checked and so on - I could never figure out how to get it to just do what I wanted.
I stripped down the template into something much more spares, without all the gradients and animations, then I added back in a few animations and triggers to make it do about what I wanted it to do.
The visual effect is like this. ON:
OFF:
The XAML I used:
<ResourceDictionary xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml">
<Style x:Key = "ToggleButtonStyle3"
TargetType = "ToggleButton">
<!-- This is a style (template?) for a toggle button. I wanted it to
change to a contrasty color when depressed. This took me a
loooooong time and much trial and error to figure out. The visual
effect is somewhat like the buttons in the compile output log in
Visual Studio, in which you can toggle the display of errors and
warnings.
-->
<Setter Property="Background" Value="#FFF7F0D2"/>
<Setter Property="Foreground" Value="#FF000000"/>
<Setter Property="Padding" Value="3"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="BorderBrush">
<Setter.Value>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#FFC4BC64" Offset="0"/>
<GradientStop Color="#FFADA658" Offset="0.375"/>
<GradientStop Color="#FFA19A52" Offset="0.375"/>
<GradientStop Color="#FF847E43" Offset="1"/>
</LinearGradientBrush>
</Setter.Value>
</Setter>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ToggleButton">
<Grid x:Name="ButtonGrid">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal"/>
<VisualState x:Name="MouseOver">
<Storyboard>
<DoubleAnimation Duration="0" Storyboard.TargetName="InnerRectangle" Storyboard.TargetProperty="Opacity" To="0.3"/>
</Storyboard>
</VisualState>
<VisualState x:Name="Pressed">
<Storyboard>
<ColorAnimation Duration="00:00:00"
Storyboard.TargetName="InnerRectangle"
Storyboard.TargetProperty="(Rectangle.Fill).(SolidColorBrush.Color)"
To="#FFF5BF0F"/>
</Storyboard>
</VisualState>
<VisualState x:Name="Disabled">
<Storyboard>
<DoubleAnimation Duration="0" Storyboard.TargetName="DisabledVisualElement" Storyboard.TargetProperty="Opacity" To=".55"/>
</Storyboard>
</VisualState>
</VisualStateGroup>
<VisualStateGroup x:Name="CheckStates">
<VisualState x:Name="Checked">
<Storyboard>
<ColorAnimation Duration="00:00:00"
Storyboard.TargetName="InnerRectangle"
Storyboard.TargetProperty="(Rectangle.Fill).(SolidColorBrush.Color)"
To="#FFF5D018"/>
</Storyboard>
</VisualState>
<VisualState x:Name="Unchecked"/>
</VisualStateGroup>
<VisualStateGroup x:Name="FocusStates">
<VisualState x:Name="Focused">
<Storyboard>
<DoubleAnimation Duration="0" Storyboard.TargetName="FocusVisualElement" Storyboard.TargetProperty="Opacity" To="1"/>
</Storyboard>
</VisualState>
<VisualState x:Name="Unfocused" />
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Border x:Name ="ButtonBorder"
CornerRadius ="1"
Background ="{TemplateBinding Background}"
BorderThickness ="{TemplateBinding BorderThickness}"
BorderBrush ="{TemplateBinding BorderBrush}">
<Border x:Name="InnerButtonBorder"
CornerRadius="1"
BorderThickness="2"
Background="#FFFAEB16">
<Rectangle x:Name="InnerRectangle" Opacity="1" Fill="#F7F0D2" />
</Border>
</Border>
<ContentPresenter
x:Name="contentPresenter"
Content="{TemplateBinding Content}"
ContentTemplate="{TemplateBinding ContentTemplate}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
TextBlock.Foreground="{TemplateBinding Foreground}"
Margin="{TemplateBinding Padding}"/>
<Rectangle x:Name="DisabledVisualElement" RadiusX="3" RadiusY="3" Fill="#FFFFFFFF" Opacity="0" IsHitTestVisible="false" />
<Rectangle x:Name="FocusVisualElement" RadiusX="2" RadiusY="2" Margin="1" Stroke="#FFD1C44D" StrokeThickness="1" Opacity="0" IsHitTestVisible="false" />
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="ToggleButton.IsChecked" Value="True">
<!-- This setter hides the desired element when the ToggleButton's initial state is checked -->
<Setter TargetName="ButtonBorder" Property="Background" Value="#FFF5D018"/>
<Setter TargetName="contentPresenter" Property="TextBlock.Foreground" Value="#FF000000"/>
</Trigger>
<Trigger Property="ToggleButton.IsChecked" Value="False">
<Setter TargetName="contentPresenter" Property="TextBlock.Foreground" Value="#78999999"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
I put that into a separate file, call it ToggleButtonStyle3.xaml. Then I use it like this:
<Window.Resources>
<ResourceDictionary>
<Style ....
</Style>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Resources/ToggleButtonStyle3.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Window.Resources>
....
<ToggleButton Name ="btnShowAlerts"
IsChecked ="{Binding Path=ShowAlerts, Mode=TwoWay}"
Style ="{StaticResource ToggleButtonStyle3}"
Content ="alerts"
FontSize ="9"
Padding ="8,2"
Margin ="0"
ClickMode ="Press"
/>
I don't know if that's the best way to do things. I know that it doesn't keep with the "theme" of the desktop. I know it's probably pretty basic. I just know that it took me a loooong time to figure out how to get a ToggleButton that changed color.

VisualStateManager does nothing (silverlight)

I am building a custom control using studio 2010 and silverlight 4.
I am trying to use the visual state manager.
With the following xml:
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:vsm="clr-namespace:System.Windows;assembly=System.Windows"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:controls="clr-namespace:SilverView">
<Style TargetType="controls:ScaleImage">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="controls:ScaleImage">
<Grid>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualStateGroup.Transitions>
<VisualTransition To="MouseOver"
GeneratedDuration="0:0:.5"/>
<VisualTransition To="Normal"
GeneratedDuration="0:0:.5"/>
</VisualStateGroup.Transitions>
<VisualState x:Name="Normal">
<Storyboard>
<DoubleAnimation
Storyboard.TargetName="img"
Storyboard.TargetProperty="Width"
From="50" To="100"/>
</Storyboard>
</VisualState>
<VisualState x:Name="MouseOver">
<Storyboard>
<DoubleAnimation
Storyboard.TargetName="img"
Storyboard.TargetProperty="Width"
From="50" To="100"/>
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Image Name="img" Width="50">
<Image.RenderTransform>
<ScaleTransform x:Name="scale"/>
</Image.RenderTransform>
</Image>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
Nothing happens when I mouse over the image.
How do I get the image to enlarge when the mouse is over it?
Thanks
The VisualStateManager.VisualStateGroups attached property defines the set of visual states however the names of the groups and the names of the states are just names, they do not actually enable the functionality they describe automatically.
It's up to code in your control to decide when it is in a specific state and then inform the VisualStateManager of that choice. You do that with code like this:-
VisualStateManager.GotoState(this, "MouseOver", true);
Typically you would collect information like whether the mouse is over the control via the various control events and have a central UpdateVisualState function that sets all the appropriate states.
In the XAML above you are only defining state groups and states with names like "MouseOver". You are not actually causing the state to change, as they are apparently not connected to any events.
If you are not already, try using GoToState behaviours to trigger the state changes of your control.
Do you have any more code or XML that triggers a state change?

How to set Viewbox content based on DataTrigger

I've video player with two button: Play and Pause.
I want to use only one button. when user clicks on Play, the button appearance will changed to Pause and vice versa.
What is the better approach to achieve that task without using cs code behind?
I've tried to use DataTrigger to my IsPlaying property, but with no much success....
Here is my code:
<Window.Resources>
<Viewbox x:Key="viewboxSource" >
<Viewbox.Triggers>
<DataTrigger Binding="{Binding IsPlaying}" Value="True">
<Setter Property="Path">
<Setter.Value>
<Path Stroke="Black" StrokeThickness="1" Fill="AliceBlue">
<Path.Data>
<GeometryGroup>
<EllipseGeometry Center="100,100" RadiusX="100" RadiusY="100"/>
</GeometryGroup>
</Path.Data>
</Path>
</Setter.Value>
</Setter>
</DataTrigger>
</Viewbox.Triggers>
</Viewbox>
</Window.Resources>
<StackPanel>
<Button Content="{StaticResource viewboxSource}"></Button>
</StackPanel>
But I gut an error that says " 'Path' member is not valid because it does not have a qualifying type name " .
Can anyone can help or give me a better solution?
These kind of behaviour fits toggle button patern.
Make a style in your resources
<Style x:Key="PlayToggleButtonStyle" TargetType="ToggleButton" >
and then define a templeate in it
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ToggleButton">
What is the most important here is to use VisualStateManager.
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Disabled"/>
<VisualState x:Name="Normal"/>
<VisualState x:Name="MouseOver"/>
<VisualState x:Name="Checked">
<Storyboard>
<DoubleAnimation Duration="0" To="2" Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.TranslateX)" Storyboard.TargetName="border" />
<ColorAnimation Duration="0:0:0.2" To="#FF392929" Storyboard.TargetProperty="(Border.Background).(GradientBrush.GradientStops)[0].(GradientStop.Color)" Storyboard.TargetName="border"/>
</Storyboard>
</VisualState>
<VisualState x:Name="Pressed">
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
I use 2 animation. One moves button for 2 pixels and second change the gradient which gives a nice experience.
The only drawback is you need to use storyboards to handle these states. You need to add a Path object which I called Geometry nad mainupulate it.
<Storyboard Storyboard.TargetName="Geometry"
Storyboard.TargetProperty="Data">
<ObjectAnimationUsingKeyFrames>
<DiscreteObjectKeyFrame KeyTime="0" Value=""/> <!-- place the data here (how your button looks like) -->
</ObjectAnimationUsingKeyFrames>
</Storyboard>
But IMHO the better solution is to place 2 Path object in the template that on is over another and change the opacity of the top-most one.
<Storyboard>
<DoubleAnimation Storyboard.TargetName="TopGeometry" Storyboard.TargetProperty="Opacity" Duration="0:0:0.5" To="0.0">
<DoubleAnimation.EasingFunction>
<QuadraticEase EasingMode="EaseIn"/>
</DoubleAnimation.EasingFunction>
</DoubleAnimation>
</Storyboard>
You would have a nice transition between these two states. What is more, no data is needed f.e IsPLaying property.

Resources