Quick One regarding Margins and Storyboards - wpf

Just a quick question, I've been searching for ages on Google. I have a storyboard:
<Storyboard x:Key="ViewLeftToRight" AccelerationRatio=".5" DecelerationRatio=".5">
<DoubleAnimation Storyboard.TargetName="ReferenceInfo" Storyboard.TargetProperty="Margin" Duration="0:0:0.15" To="{Binding, Width},0,0,0"/>
</Storyboard>
It doesn't work. I was wondering if there is a way for me to bind the Width of the control to the "left" margin. If I need to use a converter, could you possibly show how it would be written in XAML in the above example?
Thanks!

No, you can't bind an animation to Margin, because it does not define a corresponding dependency property. There are several alternatives, here are two:
Place your object in a Canvas and animate Canvas.Left and Canvas.Top
Define a RenderTransform on your object, and animate its X and Y properties.
1)
<Canvas>
<TextBlock Text="test" x:Name="ReferenceInfo" Canvas.Left="0" Canvas.Top="0" />
</Canvas>
Here your storyboard short target the same element ReferenceInfo, but target the attached properties, which you denote using brackets like "(Canvas.Left)":
<DoubleAnimation
Storyboard.TargetName="ReferenceInfo"
Storyboard.TargetProperty="(Canvas.Left)" Duration="0:0:0.15"
To="{Binding Width}"/>
2)
<TextBlock Text="test" x:Name="ReferenceInfo">
<TextBlock.RenderTransform>
<TranslateTransform x:Name="TranslateReferenceInfo" X="0" Y="0" />
</TextBlock.RenderTransform>
</TextBlock>
The animation would then reference the TranslateTransform itself by name:
<DoubleAnimation
Storyboard.TargetName="TranslateReferenceInfo"
Storyboard.TargetProperty="X" Duration="0:0:0.15"
To="{Binding Width}"/>

Related

Adding content/text in rectangle WPF

This is my code for rectangle :
<Rectangle x:Name="rect1" Grid.Column="1" Fill="#FF5C626C" HorizontalAlignment="Left" Height="50" Margin="36,171,0,0" StrokeThickness="2" VerticalAlignment="Top" Width="358" RadiusX="30" RadiusY="50">
<Rectangle.Triggers>
</Rectangle.Triggers>
<Rectangle.Style>
<Style TargetType="Rectangle">
<Style.Triggers>
<EventTrigger RoutedEvent="Rectangle.MouseEnter">
<BeginStoryboard>
<Storyboard>
<ParallelTimeline >
<ColorAnimation Storyboard.TargetProperty="Fill.Color" To="#FF767C84" />
</ParallelTimeline>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
<EventTrigger RoutedEvent="Rectangle.MouseLeave">
<BeginStoryboard>
<Storyboard>
<ParallelTimeline >
<ColorAnimation Storyboard.TargetProperty="Fill.Color" To="#FF5C626C" />
</ParallelTimeline>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Style.Triggers>
</Style>
</Rectangle.Style>
</Rectangle>
My question is how do i add a text/content in the rectangle ?
One might suggest using a code block, but if u go through my code, youu'll notice that the rectangle changes it's color on mouseover.So if i put a textblock over the rectangle,the mouseover doesn't work properly(as the textblock covers the entire rectangle).
Another suggestion would be to use a border.But i am not sure about this as i need to find the code to apply mouse over effect on a border.
The next suggestion might be to use a button instead.I would've but my rectangle has corner radius and is a bit round-shaped which, if i use a button, would be hard to achieve.
So how do i add content/text inside the rectangle?
If you feel you definitely have to use a rectangle, put it in a grid and add a TextBlock element above it.
By setting the TextBlock's IsHitTestVisible property to False all hit-testing (mouse events) will be ignored on it and fall through to your rectangle.
<Grid>
<Rectangle (...your attributes here...)>
(...your rectangle code here...)
</Rectangle>
<TextBlock Text="Hello World!" IsHitTestVisible="False" />
</Grid>

How to dynamically size a rectangular path with animated stroke thickness?

I have a Rectangle and a Path defined by a RectangleGeometry:
<Grid>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<Rectangle Grid.Row="0" Stroke="Red" Width="{Binding RctWidth}"/>
<Path Grid.Row="1" Stroke="Red">
<Path.Data>
<RectangleGeometry Rect="0,0,50,10"/>
</Path.Data>
<Path.Triggers>
<EventTrigger RoutedEvent="Path.Loaded">
<BeginStoryboard>
<Storyboard TargetProperty="StrokeThickness">
<DoubleAnimation RepeatBehavior="Forever" From="1" To="3" Duration="0:0:0.5"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Path.Triggers>
</Path>
</Grid>
The rectangle changes its width dynamically according to the binding.
The rectangular Path has an animation applied on its StrokeThickness.
I want the rectangular Path to exactly match that rectangle in size, but in such a manner that the stroke thickness animation won't affect that (the thicker stroke should make the Path actually a little bit bigger than the Rectangle - that's the intended behavior).
How can I do that?
Note, that I cannot use the Stretch="Fill" property on the Path. In that case, the stroke thickness will grow only inside the Paths bounds, but I want to keep the default behavior of stroke's growing both in the inner and outer directions.
Furthermore, I cannot change the view model the Rectangle's width is bound to. It's an external component that I'm not allowed to modify.
I could get rid of that Rectangle actually. The important thing for me is the Path and its dynamically changing width.
As commented, the effect of stroke thickness growing only to the inside can be canceled by negative margins.
For an animation that changes the thickness from 1 to 3, the margin needs to change from 0 to -1 (compensate for half of the thickness change):
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty="StrokeThickness" RepeatBehavior="Forever" From="1" To="3" Duration="0:0:0.5"/>
<ThicknessAnimation Storyboard.TargetProperty="Margin" RepeatBehavior="Forever" From="0" To="-1" Duration="0:0:0.5"/>
</Storyboard>
</BeginStoryboard>
With this, you can use your solution with Stretch="Fill", whatever it might look like.

How to get the position of a control in XAML?

I would like to get the position of a control relative to its parent, or just any kind of position, doesn't really matter. But I want to do this only in XAML without any code behind. I have a grid 5x3, and the button is located in 3rd row and 2nd column. So, basically I would like to get the width of first two rows of the grid, and the width of the first column of the gird.
I want to know the position of the button in pixels, because I want to do translation animation like this:
<DoubleAnimation Storyboard.TargetName="Studio" Storyboard.TargetProperty="RenderTransform.(TranslateTransform.X)" From="500" To="0" Duration="0:0:2">
but instead of using hardcoded value of 500, I want it to be anything that corresponds to the button's horisontal position in pixels
Something like the XAML below might work for you. It is inspired by your idea of a transparent dummy Rectangle that fills the columns left of the Button.
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Rectangle x:Name="dummy" Grid.ColumnSpan="2"/>
<Button Grid.Column="2" VerticalAlignment="Center" Content="Click">
<Button.RenderTransform>
<TransformGroup>
<ScaleTransform ScaleX="-1"/>
<TranslateTransform/>
<ScaleTransform ScaleX="-1"/>
</TransformGroup>
</Button.RenderTransform>
<Button.Triggers>
<EventTrigger RoutedEvent="Button.Click">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
Storyboard.TargetProperty="RenderTransform.Children[1].X"
To="{Binding ActualWidth, ElementName=dummy}"
Duration="0:0:2"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Button.Triggers>
</Button>
</Grid>
Instead of declaring the RenderTransform as shown above you may perhaps better use a binding converter to invert the value of the dummy Rectangle's ActualWidth property.

XAML animation of height of control with dynamic content

I have a panel that should be minimized unless the user hovers the mouse over the panel. It is implemented using a storyboard that lets the height of the panel grow when the use puts the mouse over the control. At the moment the target height is hard coded to 400 which is a bad solution as the content of the panel will be different each time the application starts (it is static during execution).
How do you create an animation that lets the panel grow to the size of the current content?
<Window x:Class="MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="MainWindow" Height="500" Width="525">
<Grid>
<Border Margin="10,0" Background="LightGray" HorizontalAlignment="Left" VerticalAlignment="Top" CornerRadius="0,0,8,8">
<Border.Effect>
<DropShadowEffect Opacity="0.5"/>
</Border.Effect>
<Border.Triggers>
<EventTrigger RoutedEvent="Border.MouseEnter">
<BeginStoryboard>
<BeginStoryboard.Storyboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty="Height"
From="25"
To="400"
Duration="0:0:0.2" />
</Storyboard>
</BeginStoryboard.Storyboard>
</BeginStoryboard>
</EventTrigger>
<EventTrigger RoutedEvent="Border.MouseLeave">
<BeginStoryboard>
<BeginStoryboard.Storyboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty="Height"
From="400"
To="25"
Duration="0:0:0.2" />
</Storyboard>
</BeginStoryboard.Storyboard>
</BeginStoryboard>
</EventTrigger>
</Border.Triggers>
<StackPanel Margin="5">
<TextBlock Height="25" Text="My items panel" />
<ListBox MinWidth="150" MinHeight="100" ItemsSource="{Binding MyItems}" />
</StackPanel>
</Border>
</Grid>
Edit: I have tried with binding to the Height of the StackPanel but that didn't really help as it didn't take the margins of the stackpanel into account thus making the panel shorter than needed.
<DoubleAnimation Storyboard.TargetProperty="Height"
From="{Binding ElementName=NameOfStackPanel, Path=ActualHeight}"
To="25"
Duration="0:0:0.2" />
You could create a converter to handle adding the margins to the ActualHeight of your StackPanel. You could even use a multivalue convertor so you could bind the margin too and not have to hardcode a fudge factor. Finally, you could probably wrap your stackpanel in another panel (without margins) and bind to the height of that instead.

Animating text color

I need to animate the text color of a custom control between two colors, which are read from two Brush properties of the custom control. My resources look like this:
<SolidColorBrush x:Key="TextBrush">{TemplateBinding Foreground}</SolidColorBrush>
<SolidColorBrush x:Key="AltTextBrush">{TemplateBinding ForegroundAlt}</SolidColorBrush>
Right now, I am trying to animate using a ColorAnimation:
<ColorAnimation Storyboard.TargetName="MyControlText" Storyboard.TargetProperty="Foreground" To="{StaticResource AltTextBrush}" Duration="00:00:00.3000000" />
The ColorAnimation seems to want a Color object, rather than the Brush I am trying to pass. I think I can write an IValueConverter to get the color from the brush, but before I do that, I want to see if there is a simpler way to do the job. Here are my questions:
-- Is there a simple way to animate between two brush resources, or do I need to extract the color for animation?
-- If I need to extract the colors, is an IValueConverter best practice?
-- And finally, amI headed down the right road, or is there a simpler solution to this problem?
Thanks for your help.
Tried with using a Binding and it seems to be working like this
To="{Binding Source={StaticResource TextBrush}, Path=Color}"
Here's a xaml example
<Window.Resources>
<SolidColorBrush x:Key="TextBrush">Black</SolidColorBrush>
<Storyboard x:Key="blinkAnimation" Duration="0:0:5" >
<ColorAnimation Storyboard.TargetProperty="(TextBlock.Foreground).(SolidColorBrush.Color)"
Storyboard.TargetName="TitleTextBlock"
To="{Binding Source={StaticResource TextBrush}, Path=Color}"
AutoReverse="True"
Duration="0:0:2"/>
</Storyboard>
</Window.Resources>
<Grid Background="Black" Name="grid">
<TextBlock x:Name="TitleTextBlock"
Background="Black"
Text="My Text"
FontSize="32"
HorizontalAlignment="Center"
VerticalAlignment="Bottom"
Foreground="White">
<TextBlock.Triggers>
<EventTrigger RoutedEvent="Loaded">
<EventTrigger.Actions>
<BeginStoryboard>
<StaticResource ResourceKey="blinkAnimation"/>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
</TextBlock.Triggers>
</TextBlock>
</Grid>

Resources