Event triggered only when a condition occurs - c#

what I'm trying to do is basically set a condition for an event to be triggered. I have this custom control where there is a Grid that has the following behavior:
MouseOver: the Opacity of another Grid (from now on called priorityFlag and placed over the triggered one, called priorityGrid) is set from 0 to 100 and its Width is set from 10 to 20.
MouseLeave: the Opacity of the priorityFlag is set back to 0 and its Width back to 10.
MouseUp: the user clicks on one of the priorityFlag's rows and, through a command, it changes the color of the priorityGrid. When the click ends, the priorityFlag's Opacity goes to 0 and its Width is set back to 10 (basically the same behavior of the MouseLeave event).
It works just fine, but when the MouseUp occurs and the user leaves the priorityGrid, the MouseLeave event gets triggered and I obtain the following behavior (you can see me hovering a couple times over the priorityGrid and then changing the priority color):
As you can see, there is an annoying flickering effect caused by the MouseLeave event.
What I'd like to know is: can I condition a trigger in order to avoid the properties changes? It seems to me that there is no parameter allowing me to do so...
Here is the custom control XAML code:
<UserControl x:Class="CSB.Tasks.TaskListItemControl"
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:local="clr-namespace:CSB.Tasks"
xmlns:core="clr-namespace:CSB.Tasks.Core;assembly=CSB.Tasks.Core"
mc:Ignorable="d"
d:DesignHeight="70"
d:DesignWidth="400">
<!-- Custom control that represents a Task. -->
<UserControl.Resources>
<!-- The control style. -->
<Style x:Key="ContentStyle"
TargetType="{x:Type ContentControl}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ContentControl}">
<Border x:Name="ContainerBorder"
BorderBrush="{StaticResource LightVoidnessBrush}"
Background="{StaticResource VoidnessBrush}"
BorderThickness="1"
Margin="2">
<Border.InputBindings>
<MouseBinding MouseAction="LeftClick"
Command="{Binding SelectTaskCommand}"/>
</Border.InputBindings>
<!-- The grid that contains the control. -->
<Grid Name="ContainerGrid"
Background="Transparent">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<!-- Border representing the priority state of the Task:
The color is defined by a ValueConverter according to the PriorityLevel of the Task object. -->
<Border Grid.Column="0"
Name="priorityFlag"
Width="10"
HorizontalAlignment="Left"
Background="{Binding Priority, Converter={local:PriorityLevelToRGBConverter}, FallbackValue={StaticResource EmerlandBrush}}">
<Grid Name="priorityGrid"
Opacity="0"
HorizontalAlignment="Left"
Width="20">
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<Border Grid.Row="0"
Name="lowPriority"
Background="{Binding Source={x:Static core:PriorityLevel.Low}, Converter={local:PriorityLevelToRGBConverter}}">
<Border.InputBindings>
<MouseBinding MouseAction="LeftClick"
Command="{Binding SetLowPriorityCommand}"/>
</Border.InputBindings>
</Border>
<Border Grid.Row="1"
Name="mediumPriority"
Background="{Binding Source={x:Static core:PriorityLevel.Medium}, Converter={local:PriorityLevelToRGBConverter}}">
<Border.InputBindings>
<MouseBinding MouseAction="LeftClick"
Command="{Binding SetMediumPriorityCommand}"/>
</Border.InputBindings>
</Border>
<Border Grid.Row="2"
Name="highPriority"
Background="{Binding Source={x:Static core:PriorityLevel.High}, Converter={local:PriorityLevelToRGBConverter}}">
<Border.InputBindings>
<MouseBinding MouseAction="LeftClick"
Command="{Binding SetHighPriorityCommand}"/>
</Border.InputBindings>
</Border>
<Grid.Triggers>
<EventTrigger RoutedEvent="MouseEnter">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetName="priorityGrid" Storyboard.TargetProperty="Opacity" From="0" To="100" Duration="0:0:0:0.1"/>
<DoubleAnimation Storyboard.TargetName="priorityFlag" Storyboard.TargetProperty="Width" From="10" To="20" Duration="0:0:0:0.1"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
<EventTrigger RoutedEvent="MouseLeave">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetName="priorityGrid" Storyboard.TargetProperty="Opacity" From="100" To="0" Duration="0:0:0:0.1"/>
<DoubleAnimation Storyboard.TargetName="priorityFlag" Storyboard.TargetProperty="Width" From="20" To="10" Duration="0:0:0:0.1"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
<EventTrigger RoutedEvent="MouseUp">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetName="priorityGrid" Storyboard.TargetProperty="Opacity" From="100" To="0" Duration="0:0:0:0.1"/>
<DoubleAnimation Storyboard.TargetName="priorityFlag" Storyboard.TargetProperty="Width" From="20" To="10" Duration="0:0:0:0.1"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Grid.Triggers>
</Grid>
</Border>
<!-- Border containing the Task's informations. -->
<Border Grid.Column="0"
Margin="20 0 0 0"
Padding="5">
<StackPanel>
<!-- The title of the Task. -->
<TextBlock Text="{Binding Title}"
FontSize="{StaticResource TaskListItemTitleFontSize}"
Foreground="{StaticResource DirtyWhiteBrush}"/>
<!-- The customer the Taks refers to. -->
<TextBlock Text="{Binding Customer}"
Style="{StaticResource TaskListItemControlCustomerTextBlockStyle}"/>
<!-- The description of the Task. -->
<TextBlock Text="{Binding Description}"
TextTrimming="WordEllipsis"
Foreground="{StaticResource DirtyWhiteBrush}"/>
</StackPanel>
</Border>
<!-- Border that contains the controls for the Task management. -->
<Border Grid.Column="2"
Padding="5">
<!-- Selection checkbox of the Task. -->
<CheckBox VerticalAlignment="Center"
IsChecked="{Binding IsSelected}"/>
</Border>
</Grid>
</Border>
<!-- Template triggers. -->
<ControlTemplate.Triggers>
<DataTrigger Binding="{Binding IsSelected}" Value="True">
<Setter Property="Background" TargetName="ContainerBorder" Value="{StaticResource OverlayVoidnessBrush}"/>
<Setter Property="BorderBrush" TargetName="ContainerBorder" Value="{StaticResource PeterriverBrush}"/>
</DataTrigger>
<EventTrigger RoutedEvent="MouseEnter">
<BeginStoryboard>
<Storyboard>
<ColorAnimation Duration="0:0:0:0" To="{StaticResource OverlayVoidness}" Storyboard.TargetName="ContainerGrid" Storyboard.TargetProperty="Background.Color"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
<EventTrigger RoutedEvent="MouseLeave">
<BeginStoryboard>
<Storyboard>
<ColorAnimation Duration="0:0:0:0" To="Transparent" Storyboard.TargetName="ContainerGrid" Storyboard.TargetProperty="Background.Color"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</UserControl.Resources>
<!-- Content of the control: assignment of the DataContext for design-time testing. -->
<ContentControl d:DataContext="{x:Static local:TaskListItemDesignModel.Instance}"
Style="{StaticResource ContentStyle}"/>
Can anyone help me? Thank you in advance for the help.

It looks like that when you trigger the MouseUp trigger it also triggers the MouseOver trigger. Therefore, the priorityFlag's Width is changed to 20 twice during the same time. Obviously, it is twice changed back,when you move the Mouse away, once (i) via MouseLeave and once (ii) via MouseUp end of the click, also basically during the same time, which causes the flickering.
You may define a private flag property in the class containing all the mouse events, which would be set to true, when the priorityFlag's Width is set to 20 and test the flag before you set it to 20 again. Or you just test the current Width before you change it in any mouse triggered event.

Related

How to set automatically the height and width of UserControl on the value of this control after dragging it?

I create UserControl and I have it in Toolbox. When I drag a control onto the main window, the height and width properties are set to 100, not those of the control (for example 70x50). Am I able to change it?
My control:
<local:Control x:Class="Controls.Sensor"
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:local="clr-namespace:Controls"
mc:Ignorable="d"
d:DesignHeight="70" d:DesignWidth="50"
x:Name="control">
<Grid >
<Ellipse Fill="Transparent" Opacity="0.5" Grid.Row="1">
<Ellipse.Triggers>
<EventTrigger RoutedEvent="Binding.TargetUpdated" >
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard Duration="0:0:1" RepeatBehavior="Forever">
<ColorAnimationUsingKeyFrames Storyboard.TargetProperty="Fill.(SolidColorBrush.Color)">
<DiscreteColorKeyFrame KeyTime="0:0:0" Value="{Binding FirstColor, UpdateSourceTrigger=PropertyChanged, NotifyOnTargetUpdated=True}" />
<DiscreteColorKeyFrame KeyTime="0:0:0.5" Value="{Binding SecondColor, UpdateSourceTrigger=PropertyChanged, NotifyOnTargetUpdated=True}" />
</ColorAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
</Ellipse.Triggers>
</Ellipse>
</Grid>
</local:Control>
and after drag:
<Controls:Sensor HorizontalAlignment="Left" Height="100" Margin="728,524,0,0" VerticalAlignment="Top" Width="100"/>
when I expected:
<Controls:Sensor HorizontalAlignment="Left" Height="70" Margin="728,524,0,0" VerticalAlignment="Top" Width="50"/>
This very annoying bug in the Visual Studio was already reported in the past. The Visual Studio developers team wasn't going to fix it.
See the following post: WPF UserControl height always set to 100.

WPF Animation : How do i make it slide in?

So I just got into animations and I wanted to do a "Slide out" animation and I managed to do so just fine.
But now I want it to slide in with the click on the same button.
So like I click it and it slides out and then I want it to slide back in when I click it again.
WITHOUT any code behind, so just through xaml
Here is the XAML
<Grid>
<Grid.Resources>
<Storyboard x:Key="TransformImage">
<DoubleAnimation
Storyboard.TargetName="MovingImage"
Storyboard.TargetProperty="(Image.RenderTransform).(TranslateTransform.X)"
By="130" Duration="0:0:0.3">
</DoubleAnimation>
</Storyboard>
<Storyboard x:Key="TransformButton">
<DoubleAnimation
Storyboard.TargetName="btnChange"
Storyboard.TargetProperty="(Button.RenderTransform).(TranslateTransform.X)"
By="130" Duration="0:0:0.3">
</DoubleAnimation>
</Storyboard>
</Grid.Resources>
<Grid.Triggers>
<EventTrigger RoutedEvent="Button.Click" SourceName="btnChange">
<BeginStoryboard Storyboard="{StaticResource TransformImage}"/>
<BeginStoryboard Storyboard="{StaticResource TransformButton}"/>
</EventTrigger>
</Grid.Triggers>
<StackPanel Orientation="Horizontal" Margin="0">
<Image x:Name="MovingImage" Source="logo.png"
MaxWidth="120">
<Image.RenderTransform>
<TranslateTransform />
</Image.RenderTransform>
</Image>
</StackPanel>
<StackPanel
Panel.ZIndex="1"
Height="450"
Width="120"
HorizontalAlignment="Left"
Background="Black"></StackPanel>
<Button Margin="130,0,0,0" Height="40" Width="120"
Content="Show Image" x:Name="btnChange"
HorizontalAlignment="Left" >
<Button.RenderTransform>
<TranslateTransform />
</Button.RenderTransform>
</Button>
</Grid>
You need to store current state of slide animation when clicking on button and based on it run appropriate story board.
For example, you could use ToggleButton that has IsChecked property (or property in view-model).
To avoid duplicate triggers/styles I placed Image and ToggleButton in the same StackPanel.
<Grid>
<Grid.Resources>
<system:Double x:Key="SlideOffSet">130</system:Double>
<Storyboard x:Key="SlideRight">
<DoubleAnimation Storyboard.TargetProperty="(UIElement.RenderTransform).(TranslateTransform.X)"
From="0" To="{StaticResource SlideOffSet}"
Duration="0:0:0.3" />
</Storyboard>
<Storyboard x:Key="SlideLeft">
<DoubleAnimation Storyboard.TargetProperty="(UIElement.RenderTransform).(TranslateTransform.X)"
From="{StaticResource SlideOffSet}" To="0"
Duration="0:0:0.3" />
</Storyboard>
</Grid.Resources>
<StackPanel Orientation="Horizontal" Margin="0">
<StackPanel.Style>
<Style TargetType="StackPanel">
<Style.Triggers>
<DataTrigger Binding="{Binding IsChecked, ElementName=SlideState}" Value="True">
<DataTrigger.EnterActions>
<BeginStoryboard Storyboard="{StaticResource SlideRight}" />
</DataTrigger.EnterActions>
<DataTrigger.ExitActions>
<BeginStoryboard Storyboard="{StaticResource SlideLeft}" />
</DataTrigger.ExitActions>
</DataTrigger>
</Style.Triggers>
</Style>
</StackPanel.Style>
<StackPanel.RenderTransform>
<TranslateTransform />
</StackPanel.RenderTransform>
<Image Source="logo.png" MaxWidth="120" />
<ToggleButton x:Name="SlideState" Margin="10,0,0,0" Height="40" Width="120" Content="Show Image" />
</StackPanel>
<StackPanel
Panel.ZIndex="1"
Height="450"
Width="120"
HorizontalAlignment="Left"
Background="Black"></StackPanel>
</Grid>
Also, I would not recommend using By property of the DoubleAnimation:
If animation is still running and you click button again, then second animation will be started at wrong position (it will use X value from first animation, which is not finished) - Click button quickly many times and you will see the problem.
Use From and To properties instead.

WPF: Change visiable of Label when other control click

I just go to WPF and have many problems, I very much like WPF and started working with it. I just make a design with WPF:
Now, I want when I click on label (icon with 3 line), then label without icon in sidebar will hide (can hide with animation).
Here my code:
Icon button:
<DockPanel DockPanel.Dock="Left">
<!-- Minimize Sidebar -->
<Label Name="LblMinimizeSideBar" Style="{StaticResource FontAwesome}" Foreground="{DynamicResource MainColor}" FontSize="24" Margin="10 0 0 0" VerticalAlignment="Center" MouseLeftButtonDown="LblMinimizeSideBar_MouseLeftButtonDown"></Label>
</DockPanel>
Sidebar:
<StackPanel DockPanel.Dock="Left" Width="80" Background="{DynamicResource MainColor}">
<ItemsControl Name="IcTodoList">
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel IsEnabled="{Binding IsEnabled}" Orientation="Vertical" Background="{Binding Background}" SnapsToDevicePixels="True" Cursor="Hand">
<Label Style="{StaticResource FontAwesome}" HorizontalAlignment="Center" FontSize="20" Foreground="#FFF">

</Label>
<Label HorizontalAlignment="Center" Foreground="#FFF" Padding="0 0 0 10" Content="{Binding Title}"></Label>
<StackPanel.Triggers>
<EventTrigger RoutedEvent="MouseEnter">
<BeginStoryboard>
<Storyboard>
<ColorAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetProperty="(StackPanel.Background).Color">
<LinearColorKeyFrame Value="#DB1918" KeyTime="0:0:0.6"/>
</ColorAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
<EventTrigger RoutedEvent="MouseLeave">
<BeginStoryboard>
<Storyboard>
<ColorAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetProperty="(StackPanel.Background).Color">
<LinearColorKeyFrame Value="#FF5750" KeyTime="0:0:0.6"/>
</ColorAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</StackPanel.Triggers>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
Any easy way to make this?
Thankyou very much!
you can use this in the label triggers to start animation in the items control
Example
<ItemsControl Name="TheItemYouWantToChange" />
in the view resources
<!-- Begin the Storyboard -->
<EventTrigger RoutedEvent="Button.Click\MOUSEDOWN" SourceName="YOUR_LABLE\BUTTON_NAME">
<BeginStoryboard Name="MyBeginStoryboard">
<Storyboard >
<DoubleAnimation
Storyboard.TargetName="TheItemYouWantToChange"
Storyboard.TargetProperty="Opacity"
Duration="0:0:5" From="1" To="0" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
you can use animation to change opacity and visibility
for more info you can see : (the example is partly from there) http://msdn.microsoft.com/en-us/library/ms744905(v=vs.110).aspx

Animate control based on other control

I am creating a media player application and I am trying to animate hiding the controls when the mouse is not inside the program window.
I have a animation setup and working, but I can't think of how to set the EventTrigger to the parent grid rather than the grid I actually want to animate. Essentially I want to set the EventTrigger to be grdMain and animate the height of grdControls.
Animation:
<Window.Resources>
<Style x:Key="FadeInOut" TargetType="Grid">
<Style.Triggers>
<EventTrigger RoutedEvent="Control.MouseEnter">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Duration="0:0:1" To="40" Storyboard.TargetProperty="Height"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
<EventTrigger RoutedEvent="Control.MouseLeave">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Duration="0:0:1" To="0" Storyboard.TargetProperty="Height"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Style.Triggers>
</Style>
</Window.Resources>
Grids:
<Grid x:Name="grdMain" Background="Black">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<MediaElement x:Name="meVideo" IsMuted="True" Stretch="Uniform" MediaOpened="meVideo_MediaOpened" MediaEnded="meVideo_MediaEnded" Grid.RowSpan="2" />
<Grid Grid.Row="1" >
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<ProgressBar x:Name="pgbVideoTimeline" HorizontalAlignment="Stretch" Height="7" Background="#252525" Foreground="Maroon" BorderThickness="0" Grid.Row="1" MouseDown="pgbVideoTimeline_MouseDown" MouseMove="pgbVideoTimeline_MouseMove" MouseUp="pgbVideoTimeline_MouseUp" />
<Grid x:Name="grdControls" Grid.Row="2" Background="#0C0D0D" Height="0" Style="{StaticResource FadeInOut}" >
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<StackPanel x:Name="stpPlaybackControls" Orientation="Horizontal" HorizontalAlignment="Left" Grid.Column="0">
<Image x:Name="btnPlayPause" Height="30" Margin="10,0,5,0" ToolTip="Play" Source="Resources/Images/UI/Play.png" MouseEnter="btnVideoControl_MouseEnter" MouseLeave="btnVideoControl_MouseLeave" MouseUp="btnPlayPause_MouseUp" />
<Image x:Name="btnReplay" Height="20" Margin="5,0,5,0" ToolTip="Replay" Source="Resources/Images/UI/Replay.png" MouseEnter="btnVideoControl_MouseEnter" MouseLeave="btnVideoControl_MouseLeave" MouseUp="btnReplay_MouseUp" />
</StackPanel>
<StackPanel x:Name="stpMiscControls" Orientation="Horizontal" HorizontalAlignment="Right" Grid.Column="1">
<Image x:Name="btnFullScreen" Height="25" Margin="5" ToolTip="Fullscreen" Source="Resources/Images/UI/FullScreen.png" MouseEnter="btnVideoControl_MouseEnter" MouseLeave="btnVideoControl_MouseLeave" MouseUp="btnFullScreen_MouseUp" />
<Image x:Name="btnSettings" Height="30" Margin="5,5,10,5" ToolTip="Settings" Source="Resources/Images/UI/Settings.png" MouseEnter="btnVideoControl_MouseEnter" MouseLeave="btnVideoControl_MouseLeave" />
</StackPanel>
</Grid>
</Grid>
</Grid>
The rule when using Trigger (in case TargetName can't be used) is the Trigger should belong to the element which has the properties you want to modify. In this case the Trigger should belong to the grdControls. However you can use DataTrigger to walk up the tree and listen to some other property change of any visual upwards in the tree. The following code should work:
<Style x:Key="FadeInOut" TargetType="Grid">
<Style.Triggers>
<DataTrigger Binding="{Binding IsMouseOver, ElementName=grdMain}"
Value="true">
<DataTrigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Duration="0:0:1" To="40"
Storyboard.TargetProperty="Height"/>
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
<DataTrigger.ExitActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Duration="0:0:1" To="0"
Storyboard.TargetProperty="Height"/>
</Storyboard>
</BeginStoryboard>
</DataTrigger.ExitActions>
</DataTrigger>
</Style.Triggers>
</Style>
The second approach close to what Peter Dunno suggested in his comment requires you to have to set the EventTrigger directly in the Triggers property of the main Grid. You can either set the Storyboards directly or define them as Resource. Here is the code for that approach:
<Grid x:Name="grdMain" Background="Black">
<Grid.Triggers>
<EventTrigger RoutedEvent="Control.MouseEnter">
<BeginStoryboard>
<Storyboard TargetName="grdControls">
<DoubleAnimation Duration="0:0:1" To="40"
Storyboard.TargetProperty="Height"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
<EventTrigger RoutedEvent="Control.MouseLeave">
<BeginStoryboard>
<Storyboard TargetName="grdControls">
<DoubleAnimation Duration="0:0:1" To="0"
Storyboard.TargetProperty="Height"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Grid.Triggers>
<!-- remaining code -->
</Grid>
Note that the Style you define now is no longer needed.

If I need to have 60 Image controls in my application, am I going to necessarily have 60 of these huge code blocks?

Someone suggested this for me to use as an animation:
<Window x:Class="WpfApplication.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="600" Width="600">
<Window.Resources>
<Storyboard x:Key="ScaleImageStoryboard">
<DoubleAnimation Duration="0:0:0.2" From="1" To="1.2" AutoReverse="True"
Storyboard.TargetName="ScaleImage" Storyboard.TargetProperty="ScaleX"/>
<DoubleAnimation Duration="0:0:0.2" From="1" To="1.2" AutoReverse="True"
Storyboard.TargetName="ScaleImage" Storyboard.TargetProperty="ScaleY"/>
</Storyboard>
</Window.Resources>
<Grid>
<Image Name="Image" Source="C:\Users\Public\Pictures\Sample Pictures\Desert.jpg"
Stretch="Fill" Width="300" Height="300"
RenderTransformOrigin="0.5, 0.5">
<Image.RenderTransform>
<ScaleTransform x:Name="ScaleImage"/>
</Image.RenderTransform>
<Image.Triggers>
<EventTrigger RoutedEvent="Image.MouseDown">
<BeginStoryboard Storyboard="{StaticResource ScaleImageStoryboard}"/>
</EventTrigger>
</Image.Triggers>
</Image>
</Grid>
Note that a single Image declaration in XAML is more than 6 lines! :D Is there a way for me to create much much cleaner XAML without breaking this functionality?
I think the easiest solution here is to create a style for the image, where you define the triggers and storyboard
<Window.Resources>
<Style x:Key="imageStyle" TargetType="{x:Type Image}">
<Setter Property="RenderTransform">
<Setter.Value>
<ScaleTransform />
</Setter.Value>
</Setter>
<Setter Property="RenderTransformOrigin" Value="0.5, 0.5" />
<Style.Triggers>
<EventTrigger RoutedEvent="Image.MouseDown">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Duration="0:0:0.2" From="1" To="1.2" AutoReverse="True"
Storyboard.TargetProperty="RenderTransform.ScaleX"/>
<DoubleAnimation Duration="0:0:0.2" From="1" To="1.2" AutoReverse="True"
Storyboard.TargetProperty="RenderTransform.ScaleY"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Style.Triggers>
</Style>
</Window.Resources>
You can then use this style for all your images :
<Image Name="Image"
Source="C:\Users\Public\Pictures\Sample Pictures\Desert.jpg"
Stretch="Fill" Width="300" Height="300"
Style="{StaticResource imageStyle}" />
Note : I didn't test it, it might require a few modifications...
I believe that Thomas' answer is quite good. If that's still to much code for you, you can make some collection of strings (or more sophisticated objects representing your 60 images), make it available for your Window through some property and display it using ItemsControl and appropriate data template (and panel [ItemsControl.ItemsPanel property] if you want to do some fancy positioning). There's really no need for 'old shool way' in WPF ;).
<Window>
<ItemsControl ItemsSource={Binding ListOfPaths}>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Image Name="Image"
Source="{Binding}"
Stretch="Fill" Width="300" Height="300"
Style="{StaticResource imageStyle}" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Window>
For situations like this is probably better to creating objects in source code ("old school way"), but if You prefer XML you can try use XSLT to generate it (but I don't recommend it).

Categories