Animate border when label value changed - wpf

I have these border and label:
<Border x:Name="PulseBoba" Width="auto" Height="auto" Background="#FFF75959" CornerRadius="2" Margin="0" HorizontalAlignment="Left">
<Label Content="{Binding kolicina}" FontSize="20" DockPanel.Dock="Right" HorizontalAlignment="Center" VerticalAlignment="Center" FontWeight="Bold" Width="Auto" Margin="5,0">
<Label.Triggers>
<EventTrigger RoutedEvent="Binding.TargetUpdated">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
Storyboard.TargetProperty="(Label.RenderTransform).(RotateTransform.Angle)"
From="0"
To="360"
Duration="0:0:2"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Label.Triggers>
</Label>
</Border>
In my vb.net code i have this piece of code which sets values correctly and displays in label:
...
Public Event PropertyChanged As PropertyChangedEventHandler _
Implements INotifyPropertyChanged.PropertyChanged
Private Sub NotifyPropertyChanged(ByVal info As String)
RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(info))
End Sub
Public Property kolicina() As String
Get
Return m_kolicina
End Get
Set
m_kolicina = Value
NotifyPropertyChanged("kolicina")
End Set
End Property
...
How would i animate this border to blink or rotate or any other animation when value of "kolicina" is changed?

You could for example bind the Tag property of the Border and use an EventTrigger that listens to the Binding.SourceUpdated attached event:
<Border x:Name="PulseBoba" Width="auto" Height="auto" Background="#FFF75959" CornerRadius="2" Margin="0" HorizontalAlignment="Left"
Tag="{Binding kolicina, NotifyOnTargetUpdated=True}">
<Border.RenderTransform>
<RotateTransform Angle="0" />
</Border.RenderTransform>
<Border.Triggers>
<EventTrigger RoutedEvent="Binding.SourceUpdated">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
Storyboard.TargetProperty="(Border.RenderTransform).(RotateTransform.Angle)"
From="0"
To="360"
Duration="0:0:2"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Border.Triggers>
<Label Content="{Binding kolicina}" FontSize="20" DockPanel.Dock="Right" HorizontalAlignment="Center" VerticalAlignment="Center"
FontWeight="Bold" Width="Auto" Margin="5,0" />
</Border>
If you require more control, you should implement the animation programmtically. You could then for example handle the PropertyChanged event of the view model in the view and create a Storyboard yourself in the code-behind based on any condition. This is a typical example of a case where it makes perfect sense to implement view-related stuff in the view.

Related

How to set animation trigger of an object inside ItemsControl to a button at upper level?

I would like to visualize multiple circles, each of which has its own animation using a path. Now I have a button that I like to click to start animation for all these circles in the view. I am new to WPF and I would like to stick to MVVM as much as possible. What makes the most sense to me is to create ItemsControl which has Canvas in the view and binding the ItemSource to my viewmodel.
The issue I have is I don't know set up RouteEvent to button click inside the ItemsControl.
<EventTrigger RoutedEvent="Button.Click" SourceName=" PlayButton"> clearly it does not find the button with that name because the MyCircle object does not have the button. See the following for my source code.
my view (XMAL) source code
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid Grid.Row="0">
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Button x:Name="PlayButton" Click="Play_Click" Content="Play" Grid.Row="0" Grid.Column="1"/>
<Button x:Name="StopButton" Click="Stop_Click" Content="Stop" Grid.Row="1" Grid.Column="1"/>
</Grid>
<Grid Grid.Row="1">
<Canvas>
<ItemsControl ItemsSource="{Binding MyItemsModel, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas Background="Transparent"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemContainerStyle>
<Style TargetType="ContentPresenter">
<Setter Property="Canvas.Left" Value="{Binding X}"/>
<Setter Property="Canvas.Top" Value="{Binding Y}"/>
</Style>
</ItemsControl.ItemContainerStyle>
<ItemsControl.ItemTemplate>
<DataTemplate x:Name="ClockwiseBobbinsDataTemplate">
<Path Fill="Red" x:Name="ClockwiseBobbinsPath">
<Path.Data>
<EllipseGeometry x:Name="MyCircle" RadiusX="5" RadiusY="5"/>
</Path.Data>
<Path.Triggers>
<EventTrigger RoutedEvent="Button.Click" SourceName="PlayButton">
<BeginStoryboard>
<Storyboard>
<PointAnimationUsingPath
Storyboard.TargetName="MyCircle"
Storyboard.TargetProperty="Center"
Duration="0:0:10"
RepeatBehavior="Forever">
<PointAnimationUsingPath.PathGeometry>
<PathGeometry
Figures="{Binding AnimationPath}"
PresentationOptions:Freeze="True" />
</PointAnimationUsingPath.PathGeometry>
</PointAnimationUsingPath>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Path.Triggers>
</Path>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Canvas>
</Grid>
</Grid>
my viewmodel source code
public class ParentViewModel : BindableBase
{
private List<MyCircle> myItemsModel;
public List<MyCircle> MyItemsModel
{
get { return myItemsModel; }
set
{
SetProperty(ref myItemsModel, value);
}
}
public ParentViewModel()
{
// instantiate MyItemsModel
}
}
MyCircle class
public class MyCircle
{
public double X { get; set; }
public double Y { get; set; }
public PathFigureCollection AnimationPath { get; set; }
public MyCircle(double x, double Y, PathFigureCollection path)
{
// do something
}
}
To go around the issue you should use DataTrigger rather then EventTrigger in ItemsControl.ItemTemplate.
The thing is, that Path.Triggers does accept only EventTrigger so you should move the part with BeginStoryboard to the DataTemplate.Triggers.
Now is the question - which data must trigger the storyboard? You could try to add some property to the viewmodel and set and access it somehow, or add an invisible e.g. CheckBox and act with it.
So remove Path.Triggers and put its content to the DataTemplate.Triggers
<DataTemplate.Triggers>
<DataTrigger Value="True">
<DataTrigger.Binding>
<Binding Path="IsChecked" ElementName="ChbPlay"/>
</DataTrigger.Binding>
<DataTrigger.EnterActions>
<BeginStoryboard x:Name="sb1">
<Storyboard>
<SomeAnimation/>
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
<DataTrigger.ExitActions>
<StopStoryboard BeginStoryboardName="sb1"/>
</DataTrigger.ExitActions>
</DataTrigger>
</DataTemplate.Triggers>
Now you must add an invisible CheckBox and control it with your buttons:
<CheckBox x:Name="ChbPlay" Visibility="Hidden"/>
<Button x:Name="PlayButton" Content="Play" Grid.Row="0" Grid.Column="1">
<Button.Triggers>
<EventTrigger RoutedEvent="Button.Click">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard>
<BooleanAnimationUsingKeyFrames Storyboard.TargetName="ChbPlay" Storyboard.TargetProperty="IsChecked">
<BooleanAnimationUsingKeyFrames.KeyFrames>
<DiscreteBooleanKeyFrame KeyTime="0" Value="True"/>
</BooleanAnimationUsingKeyFrames.KeyFrames>
</BooleanAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
</Button.Triggers>
</Button>
<Button x:Name="StopButton" Content="Stop" Grid.Row="1" Grid.Column="1">
<Button.Triggers>
<EventTrigger RoutedEvent="Button.Click">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard>
<BooleanAnimationUsingKeyFrames Storyboard.TargetName="ChbPlay" Storyboard.TargetProperty="IsChecked">
<BooleanAnimationUsingKeyFrames.KeyFrames>
<DiscreteBooleanKeyFrame KeyTime="0" Value="False"/>
</BooleanAnimationUsingKeyFrames.KeyFrames>
</BooleanAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
</Button.Triggers>
</Button>

Navigation Bar Using WPF error (Cannot resolve all property references in the property path)

i have worked in Windows form development & new for WPF Development. i don't have any idea about Xaml development. i wrote some code but facing Error
An unhandled exception of type 'System.InvalidOperationException' occurred in PresentationFramework.dll Additional information: Cannot resolve all property references in the property path 'FrameworkElement.Width'.
Below is my Xaml Code.
<Window x:Class="MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Height="600" Width="1080" ResizeMode="NoResize" WindowStyle="None" Foreground="White"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes" >
<Window.Resources>
<Storyboard x:Key="MenuOpen">
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="FrameworkElement.Width" Storyboard.TargetName="GridMenu">
<EasingDoubleKeyFrame KeyTime="0" Value="60"></EasingDoubleKeyFrame>
<EasingDoubleKeyFrame KeyTime="0:0:0.5" Value="200"></EasingDoubleKeyFrame>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
<Storyboard x:Key="MenuClose">
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="FrameworkElement.Width" Storyboard.TargetName="GridMenu">
<EasingDoubleKeyFrame KeyTime="0" Value="200"></EasingDoubleKeyFrame>
<EasingDoubleKeyFrame KeyTime="0:0:0.5" Value="60"></EasingDoubleKeyFrame>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</Window.Resources>
<Window.Triggers>
<EventTrigger RoutedEvent="ButtonBase.Click" SourceName="ButtonOpenMenu">
<BeginStoryboard Storyboard="{StaticResource MenuOpen}"></BeginStoryboard>
</EventTrigger>
<EventTrigger RoutedEvent="ButtonBase.Click" SourceName="ButtonCloseMenu">
<BeginStoryboard Storyboard="{StaticResource MenuClose}"></BeginStoryboard>
</EventTrigger>
</Window.Triggers>
<Grid Background="LightGray">
<Grid Height="60" VerticalAlignment="Top" Background="#FF1368BD">
<TextBlock Text="Tuck Shop Management System" HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="22"></TextBlock>
<StackPanel VerticalAlignment="Center" Orientation="Horizontal" HorizontalAlignment="Right">
<TextBlock Text="User Profile" VerticalAlignment="Center" FontSize="18"></TextBlock>
<materialDesign:PopupBox Margin="10" PlacementMode="BottomAndAlignRightEdges" StaysOpen="False">
<StackPanel Width="150">
<Button Content="Account"></Button>
<Button Content="Setting"></Button>
<Button Content="Help"></Button>
<Separator></Separator>
<Button x:Name="ButtonPopoutLogout" Content="Logout" Click="ButtonPopoutLogout_Click"></Button>
</StackPanel>
</materialDesign:PopupBox>
</StackPanel>
</Grid>
<Grid x:Name="GridMenu" Width="60" HorizontalAlignment="Left" Background="#FF1A3761">
<StackPanel>
<Grid Height="150" Background="White">
<Button x:Name="ButtonCloseMenu" VerticalAlignment="Top" HorizontalAlignment="Right" Width="60" Height="60" Background="{x:Null}" BorderBrush="{x:Null}" Click="ButtonCloseMenu_Click">
<materialDesign:PackIcon Kind="ArrowLeft" Foreground="#FF1A3761" Width="25" Height="25" Visibility="Collapsed"></materialDesign:PackIcon>
</Button>
<Button x:Name="ButtonOpenMenu" VerticalAlignment="Top" HorizontalAlignment="Right" Width="60" Height="60" Background="{x:Null}" BorderBrush="{x:Null}" Click="ButtonOpenMenu_Click">
<materialDesign:PackIcon Kind="Menu" Foreground="#FF1A3761" Width="25" Height="25"></materialDesign:PackIcon>
</Button>
</Grid>
<ListView ScrollViewer.HorizontalScrollBarVisibility="Disabled" Foreground="#FF1368BD" MouseDown="ListView_MouseDown">
<ListViewItem Height="60" x:Name="Home">
<StackPanel Orientation="Horizontal">
<materialDesign:PackIcon Kind="ViewDashboard" Height="25" Width="25" Margin="10" VerticalAlignment="Center"></materialDesign:PackIcon>
<TextBlock Text="Home" VerticalAlignment="Center" Margin="20 10"></TextBlock>
</StackPanel>
</ListViewItem>
<ListViewItem Height="60">
<StackPanel Orientation="Horizontal">
<materialDesign:PackIcon Kind="Pencil" Height="25" Width="25" Margin="10" VerticalAlignment="Center"></materialDesign:PackIcon>
<TextBlock Text="Create" VerticalAlignment="Center" Margin="20 10"></TextBlock>
</StackPanel>
</ListViewItem>
<ListViewItem Height="60">
<StackPanel Orientation="Horizontal">
<materialDesign:PackIcon Kind="Ticket" Height="25" Width="25" Margin="10" VerticalAlignment="Center"></materialDesign:PackIcon>
<TextBlock Text="Ticket" VerticalAlignment="Center" Margin="20 10"></TextBlock>
</StackPanel>
</ListViewItem>
<ListViewItem Height="60">
<StackPanel Orientation="Horizontal">
<materialDesign:PackIcon Kind="Message" Height="25" Width="25" Margin="10" VerticalAlignment="Center"></materialDesign:PackIcon>
<TextBlock Text="Message" VerticalAlignment="Center" Margin="20 10"></TextBlock>
</StackPanel>
</ListViewItem>
<ListViewItem Height="60">
<StackPanel Orientation="Horizontal">
<materialDesign:PackIcon Kind="GithubBox" Height="25" Width="25" Margin="10" VerticalAlignment="Center"></materialDesign:PackIcon>
<TextBlock Text="Git Hub" VerticalAlignment="Center" Margin="20 10"></TextBlock>
</StackPanel>
</ListViewItem>
</ListView>
</StackPanel>
</Grid>
</Grid>
Also i have Code Behind Given Below.
Private Sub ButtonPopoutLogout_Click(sender As Object, e As RoutedEventArgs)
Application.Current.Shutdown()
End Sub
Private Sub ButtonOpenMenu_Click(sender As Object, e As RoutedEventArgs)
ButtonOpenMenu.Visibility = Windows.Visibility.Collapsed
ButtonCloseMenu.Visibility = Windows.Visibility.Visible
End Sub
Private Sub ButtonCloseMenu_Click(sender As Object, e As RoutedEventArgs)
ButtonOpenMenu.Visibility = Windows.Visibility.Visible
ButtonCloseMenu.Visibility = Windows.Visibility.Collapsed
End Sub
waiting for +ve response. i will be thankful to you guys in advance because i am stuck in the task.
You are missing ( ) in when setting Storyboard.TargetProperty.
You can find out more about property path here.
Just change your storyboard to:
<Storyboard x:Key="MenuOpen">
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(FrameworkElement.Width)" Storyboard.TargetName="GridMenu">
<EasingDoubleKeyFrame KeyTime="0" Value="60"></EasingDoubleKeyFrame>
<EasingDoubleKeyFrame KeyTime="0:0:0.5" Value="200"></EasingDoubleKeyFrame>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
<Storyboard x:Key="MenuClose">
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(FrameworkElement.Width)" Storyboard.TargetName="GridMenu">
<EasingDoubleKeyFrame KeyTime="0" Value="200"></EasingDoubleKeyFrame>
<EasingDoubleKeyFrame KeyTime="0:0:0.5" Value="60"></EasingDoubleKeyFrame>
</DoubleAnimationUsingKeyFrames>
</Storyboard>

FluidMoveSetTagBehavior stretching Text vertically

I've recently start to learn all about FluidMoveSetTagBehavior and FluidMoveBehavior using Microsoft Expression Blend and Visual Studio 2010. Following a few examples I've found on the web, I've created the below sample which works well apart from a small problem.
I have been trying to test creating an animation to show an update of a TextBlock when a ListViewItem is selected.
When an item is selected in the ListView the text does move to the TextBlock as per the FluidMoveBehavior but the text is stretched vertically during the animation phase. It then snaps back correctly within the TextBlock once the animation ends. I initially had this problem with horizontal stretching too but I was able to solve this adding a few HorizontalAlignment="Left" properties. No such luck VerticalAlignment properties though.
Xaml Code
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*"/>
<ColumnDefinition Width="1*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<WrapPanel>
<TextBox Height="23" Name="TextBox1" Margin="4" VerticalAlignment="Center" Width="120" />
<Button Content="Add" Margin="4" Name="Button1" VerticalAlignment="Top" Width="75" />
<Button Content="Remove" Margin="4" Name="Button2" VerticalAlignment="Top" Width="75" />
</WrapPanel>
<ListView Grid.Row="1" Height="150" Name="ListView1" SelectionMode="Single" VerticalAlignment="Top">
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel >
<i:Interaction.Behaviors>
<ei:FluidMoveBehavior Duration="0:0:0.5" AppliesTo="Children">
<ei:FluidMoveBehavior.EaseY>
<QuarticEase EasingMode="EaseInOut"/>
</ei:FluidMoveBehavior.EaseY>
<ei:FluidMoveBehavior.EaseX>
<QuarticEase EasingMode="EaseInOut"/>
</ei:FluidMoveBehavior.EaseX>
</ei:FluidMoveBehavior>
</i:Interaction.Behaviors>
</StackPanel>
</ItemsPanelTemplate>
</ListView.ItemsPanel>
<ListView.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding}" FontSize="14" HorizontalAlignment="Left" TextWrapping="Wrap"
Opacity="0" TextAlignment="Center" Height="23" >
<i:Interaction.Behaviors>
<ei:FluidMoveSetTagBehavior Tag="DataContext"/>
</i:Interaction.Behaviors>
<TextBlock.Triggers>
<EventTrigger RoutedEvent="FrameworkElement.Loaded">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty="Opacity"
Duration="00:00:01"
From="0"
To="1" BeginTime="00:00:00.4000000" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
<EventTrigger RoutedEvent="FrameworkElement.Unloaded">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty="Opacity"
Duration="00:00:01"
From="1"
To="0" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</TextBlock.Triggers>
</TextBlock>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<StackPanel Grid.Column="1" Grid.Row="1">
<TextBlock DataContext="{Binding SelectedItem, Mode=TwoWay, ElementName=ListView1}" HorizontalAlignment="Left"
TextWrapping="Wrap" FontSize="14" Text="{Binding Mode=OneWay}" Height="23" >
<i:Interaction.Behaviors>
<ei:FluidMoveBehavior InitialTag="DataContext" Duration="0:0:2">
<ei:FluidMoveBehavior.EaseX>
<CircleEase EasingMode="EaseOut"/>
</ei:FluidMoveBehavior.EaseX>
</ei:FluidMoveBehavior>
</i:Interaction.Behaviors>
</TextBlock>
</StackPanel>
</Grid>
Code Behind
Class MainWindow
Private Sub Button1_Click(sender As System.Object, e As System.Windows.RoutedEventArgs) Handles Button1.Click
ListView1.Items.Insert(0, TextBox1.Text)
End Sub
Private Sub Button2_Click(sender As System.Object, e As System.Windows.RoutedEventArgs) Handles Button2.Click
ListView1.Items.Remove(ListView1.Items(0))
End Sub
End Class
Hope someone can help.

Close popup from child button's press?

I have a Popup that contains a "close" button. The popup is opened by a toggle button (its IsOpen property is bound to a ToggleButton as provided by this answer). How can I close the popup when the button is pressed? This is my XAML:
<Canvas x:Name="LayoutRoot">
<ToggleButton x:Name="ToggleButton"
Style="{DynamicResource ToggleButtonStyle}" Height="51" Canvas.Left="2.999" Width="50.333" IsHitTestVisible="{Binding ElementName=Popup, Path=IsOpen, Mode=OneWay, Converter={StaticResource BoolInverter}}"/>
<Popup x:Name="Popup" IsOpen="{Binding IsChecked, ElementName=ToggleButton}" StaysOpen="False" AllowsTransparency="True">
<Canvas Height="550" Width="550">
<Grid Height="500" Width="500" Canvas.Left="25" Canvas.Top="25" d:LayoutOverrides="Width, Height, Margin">
<Grid.Effect>
<DropShadowEffect BlurRadius="15" ShadowDepth="0"/>
</Grid.Effect>
<Grid.RowDefinitions>
<RowDefinition Height="0.132*"/>
<RowDefinition Height="0.868*"/>
</Grid.RowDefinitions>
<Rectangle x:Name="Background" Fill="#FFF4F4F5" Margin="0" Stroke="Black" RadiusX="6" RadiusY="6" Grid.RowSpan="2"/>
<Border x:Name="TitleBar" BorderThickness="1" Height="70" VerticalAlignment="Top" Margin="0,0.5,0,0" CornerRadius="5">
<DockPanel>
<TextBlock TextWrapping="Wrap" Text="FOOBAR POPUP TITLE" FontSize="24" FontFamily="Arial Narrow" Margin="17,0,0,0" d:LayoutOverrides="Height" VerticalAlignment="Center" FontWeight="Bold"/>
<Button x:Name="CloseButton" Content="Button" VerticalAlignment="Center" DockPanel.Dock="Right" HorizontalAlignment="Right" Margin="0,0,13,0" Style="{DynamicResource CloseButtonStyle}"/>
</DockPanel>
</Border>
<Border BorderThickness="1" Height="413" Grid.Row="1" Background="#FF2F2F2F" Margin="12">
<Rectangle Fill="#FFF4F4F5" RadiusY="6" RadiusX="6" Stroke="Black" Margin="12"/>
</Border>
</Grid>
</Canvas>
</Popup>
</Canvas>
A better approach than code behind is to use an event trigger on the button click event:
<Button>
<Button.Triggers>
<EventTrigger RoutedEvent="Button.Click">
<BeginStoryboard>
<Storyboard>
<BooleanAnimationUsingKeyFrames Storyboard.TargetProperty="IsChecked" Storyboard.TargetName="ToggleButton">
<DiscreteBooleanKeyFrame KeyTime="0:0:0" Value="False" />
</BooleanAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Button.Triggers>
</Button>
Disclaimer: I haven't run this code through VS so it might have a typo or 2
Other answers didn't work for me, because I was using a DataTemplate for the buttons inside the popup. After lot's of searching I found that I should use Storyboard.Target instead of Storyboard.TargetName. Otherwise the x:Name was not found and there was some namespace exception.
<ToggleButton x:Name="MyToggleButtonName" Content="{Binding MyToggleButtonString}"/>
And later inside the Popup that has a ListBox which is populated from some ItemsSource:
<ListBox.ItemTemplate>
<DataTemplate>
<Button Content="{Binding Name, Mode=OneWay}"
Command="{StaticResource MyCommandThatTakesAParameter}"
CommandParameter="{Binding Name}">
<Button.Triggers>
<EventTrigger RoutedEvent="Button.Click">
<BeginStoryboard>
<Storyboard>
<BooleanAnimationUsingKeyFrames Storyboard.TargetProperty="IsChecked" Storyboard.Target="{Binding ElementName=MyToggleButtonName}">
</BooleanAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Button.Triggers>
</Button>
</DataTemplate>
</ListBox.ItemTemplate>
This way it is possible to get a somewhat working ComboBox which can execute commands with the buttons inside it. (A normal ComboBox can't launch commands for some odd reason.)
One way of doing it is to add event handler for your CloseButton:
<Button x:Name="CloseButton" Click="OnButtonClick" Content="Button" VerticalAlignment="Center" DockPanel.Dock="Right" HorizontalAlignment="Right" Margin="0,0,13,0" Style="{DynamicResource CloseButtonStyle}"/>
And in OnButtonClick event handler set state of your
TuggleButton.IsChecked = false;
I have't tested code in VS, so there might be some typos

How to make a listboxitem expand on selection?

I have a situation where I want the user to make choices in a certain order (first I want the user to select the database, then I want him to tell me his credentials).
To do this I have challenged myself with the task of making a listbox that expands the item on selection.
To make it expand is not difficult (something like
Visibility="{Binding Path=IsSelected
, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListBoxItem}}
, Converter={StaticResource VisibilityOfBool}
, ConverterParameter=False}"
will do the trick).
The problem is that the transition is instantaneous; it is hard for the user to see what happened. What I should like to do is an animated expansion of the hidden panel...
Here is a page to demonstrate what I mean:
<Page
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:system="clr-namespace:System;assembly=mscorlib"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300"
Title="SlidingExpansionOnSelected">
<!--x:Class="TorsSandBox.Pages.SlidingExpansionOnSelected"-->
<Page.Resources>
<DataTemplate x:Key="daItemTemplate">
<StackPanel Margin="10">
<StackPanel.Triggers>
<EventTrigger RoutedEvent="ListBoxItem.Selected">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
Storyboard.TargetName="daTransform"
Storyboard.TargetProperty="ScaleY"
To="1.0" Duration="0:0:1"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
<EventTrigger RoutedEvent="ListBoxItem.Unselected">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
Storyboard.TargetName="daTransform"
Storyboard.TargetProperty="ScaleY"
To="0" Duration="0:0:1"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
</StackPanel.Triggers>
<TextBlock x:Name="Header" Text="{Binding}"/>
<Border x:Name="daBorder"
BorderThickness="3" BorderBrush="DarkOrange" CornerRadius="5"
HorizontalAlignment="Stretch"
Margin="20 10 10 10"
MinHeight="100"
>
<Border.LayoutTransform>
<ScaleTransform x:Name="daTransform" ScaleX="1" ScaleY="0"/>
</Border.LayoutTransform>
<TextBlock Text="Hide this until selected"
HorizontalAlignment="Center" VerticalAlignment="Center" />
</Border>
</StackPanel>
</DataTemplate>
</Page.Resources>
<ListBox
HorizontalContentAlignment="Stretch"
ItemTemplate="{StaticResource daItemTemplate}"
>
<system:String>First row</system:String>
<system:String>Second row</system:String>
<system:String>Third row</system:String>
<system:String>Last row</system:String>
</ListBox>
</Page>
The triggers doesn't work, but that's because I can't make them fire...Anybody knows how to make this happen?
Regards
Tor Thorbergsen
This stuff is way too complicated...
What's wrong with your approach is that the animation only affects elements lower on the VisualTree, that means the container is not affected as far as i know.
Specifying the property path in animations is a major pain, i say. I could not access the border inside the StackPanel because its Children property is not a dependency property and the whole syntax is rather unusual.
Anyway, here's a hacky solution, that works:
<Style TargetType="ListBoxItem">
<Style.Resources>
<Storyboard x:Key="OnSelected1"/>
</Style.Resources>
<Setter Property="Tag">
<Setter.Value>
<sys:Double>0</sys:Double>
</Setter.Value>
</Setter>
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<StackPanel x:Name="stackPanel" Margin="10">
<TextBlock x:Name="Header" Text="{Binding}"/>
<Border x:Name="daBorder"
BorderThickness="3" BorderBrush="DarkOrange" CornerRadius="5"
HorizontalAlignment="Stretch"
Margin="20 10 10 10"
MinHeight="100">
<Border.LayoutTransform>
<ScaleTransform ScaleX="1" ScaleY="{Binding RelativeSource={RelativeSource AncestorType=ListBoxItem}, Path=Tag}"/>
</Border.LayoutTransform>
<TextBlock Text="Hide this until selected" HorizontalAlignment="Center" VerticalAlignment="Center" />
</Border>
</StackPanel>
</DataTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<EventTrigger RoutedEvent="ListBoxItem.Selected">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
Storyboard.TargetProperty="(ListBoxItem.Tag)"
Storyboard.TargetName="{x:Null}"
To="1.0" Duration="0:0:1"/>
</Storyboard>
</BeginStoryboard>
<BeginStoryboard Storyboard="{StaticResource OnSelected1}"/>
</EventTrigger.Actions>
</EventTrigger>
<EventTrigger RoutedEvent="ListBoxItem.Unselected">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
Storyboard.TargetProperty="(ListBoxItem.Tag)"
Storyboard.TargetName="{x:Null}"
To="0" Duration="0:0:1"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
</Style.Triggers>
</Style>
I've tried to extract the ScaleTransform and reference it both in the animation and in the Border but that did not work for whatever reason.
EDIT:
Ok, I've figure it out. I've created an attached property for this (instead of using Tag).
public static class ListBoxHelper
{
public static readonly DependencyProperty ScaleYAnimationProperty =
DependencyProperty.RegisterAttached("ScaleYAnimation", typeof(double), typeof(ListBoxHelper), new FrameworkPropertyMetadata(0d));
public static double GetScaleYAnimation(UIElement element)
{
return (double)element.GetValue(ScaleYAnimationProperty);
}
public static void SetScaleYAnimation(UIElement element, double value)
{
element.SetValue(ScaleYAnimationProperty, value);
}
}
<ListBox ItemsSource="{Binding Contacts}" HorizontalContentAlignment="Stretch">
<ListBox.Resources>
<Style TargetType="ListBoxItem" BasedOn="{StaticResource {x:Type ListBoxItem}}">
<Setter Property="controls:ListBoxHelper.ScaleYAnimation" Value="0"/>
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<StackPanel>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="40"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="100"/>
</Grid.ColumnDefinitions>
<controls:CircleContentControl Grid.Column="0" Width="40" Height="40">
<Image Source="{Binding Image}"/>
</controls:CircleContentControl>
<TextBlock Text="{Binding FullName}" Grid.Column="1" Margin="10,0,5,0" VerticalAlignment="Center"/>
<TextBlock Text="{Binding PhoneNumber}" Grid.Column="2" VerticalAlignment="Center" FontStyle="Italic">
<TextBlock.LayoutTransform>
<ScaleTransform ScaleX="0.7" ScaleY="0.7"/>
</TextBlock.LayoutTransform>
</TextBlock>
<StackPanel Orientation="Horizontal" Grid.Column="3" VerticalAlignment="Center" HorizontalAlignment="Center">
<Button cal:Message.Attach="Call($dataContext)" Width="30" Height="30" Style="{StaticResource ContactDialButtonStyle}">
<Rectangle Width="10" Height="10" Fill="{Binding Path=Foreground, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Button}}}">
<Rectangle.OpacityMask>
<VisualBrush Stretch="Fill" Visual="{DynamicResource appbar_phone}" />
</Rectangle.OpacityMask>
</Rectangle>
</Button>
</StackPanel>
</Grid>
<Border x:Name="daBorder"
BorderThickness="3" BorderBrush="DarkOrange" CornerRadius="5"
HorizontalAlignment="Stretch"
Margin="20 10 10 10"
MinHeight="100">
<Border.LayoutTransform>
<ScaleTransform ScaleX="1" ScaleY="{Binding RelativeSource={RelativeSource AncestorType=ListBoxItem}, Path=(controls:ListBoxHelper.ScaleYAnimation)}"/>
</Border.LayoutTransform>
<TextBlock Text="Hide this until selected" HorizontalAlignment="Center" VerticalAlignment="Center" />
</Border>
</StackPanel>
</DataTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<EventTrigger RoutedEvent="ListBoxItem.Selected">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
Storyboard.TargetProperty="(controls:ListBoxHelper.ScaleYAnimation)"
Storyboard.TargetName="{x:Null}"
To="1.0" Duration="0:0:1"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
<EventTrigger RoutedEvent="ListBoxItem.Unselected">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
Storyboard.TargetProperty="(controls:ListBoxHelper.ScaleYAnimation)"
Storyboard.TargetName="{x:Null}"
To="0.0" Duration="0:0:1"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
</Style.Triggers>
</Style>
</ListBox.Resources>
</ListBox>
I'm using #H.B solution. It works the first time the list is loaded. However, if I expand one listboxitem, switch to another tab and go back to the tab where listbox is, an exception is thrown:
System.Windows.Data Error: 23 : Cannot convert '<null>' from type '<null>' to type 'System.Double' for 'en-US' culture with default conversions; consider using Converter property of Binding. NotSupportedException:'System.NotSupportedException: DoubleConverter não pode ser convertido de (nulo).
em System.ComponentModel.TypeConverter.GetConvertFromException(Object value)
em System.ComponentModel.TypeConverter.ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, Object value)
em System.ComponentModel.BaseNumberConverter.ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, Object value)
em MS.Internal.Data.DefaultValueConverter.ConvertHelper(Object o, Type destinationType, DependencyObject targetElement, CultureInfo culture, Boolean isForward)'
System.Windows.Data Error: 6 : 'ObjectSourceConverter' converter failed to convert value '<null>' (type '<null>'); fallback value will be used, if available. BindingExpression:Path=Tag; DataItem='ListBoxItem' (Name=''); target element is 'ScaleTransform' (HashCode=48000142); target property is 'ScaleY' (type 'Double') NotSupportedException:'System.NotSupportedException: DoubleConverter não pode ser convertido de (nulo).
em MS.Internal.Data.DefaultValueConverter.ConvertHelper(Object o, Type destinationType, DependencyObject targetElement, CultureInfo culture, Boolean isForward)
em MS.Internal.Data.ObjectSourceConverter.Convert(Object o, Type type, Object parameter, CultureInfo culture)
em System.Windows.Data.BindingExpression.ConvertHelper(IValueConverter converter, Object value, Type targetType, Object parameter, CultureInfo culture)'
Anyone having this too?
You should not need the ListBoxItem prefix on your events, just use "Selected" and "Unselected".
Another alternative to try is a property trigger:
https://web.archive.org/web/20120225232943/http://en.csharp-online.net/WPF_Styles_and_Control_Templates%E2%80%94Property_Triggers

Resources