I am coding some basic animation and would like to see it's render without building/deploying the entire project. If I remember correctly, I already managed to see such preview when creating animation in codebehind. I am now using the xaml and am trying to find out how to get the same result.
I know there's the "Blend" solution, but i'd like to avoid it.
The "Turn ON render effects" and "Enable project code" buttons are active in xaml designer.
<Image
Name="CompressorGreySmokeNormalWay"
Source="/VirtualTrain.Setrag.GT46AC;component/Resources/Images/Common/SmokeIconGrey.png"
Width="{Binding ActualWidth, Mode=OneWay, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Canvas}}}"
Height="{Binding ActualHeight, Mode=OneWay, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Canvas}}}" >
<Image.Triggers>
<EventTrigger
RoutedEvent="UserControl.Loaded">
<BeginStoryboard>
<Storyboard
AutoReverse="True"
Storyboard.TargetProperty="Opacity">
<DoubleAnimation
RepeatBehavior="Forever"
BeginTime="0:0:00.00"
From="1.0"
To="0.0"
Duration="0:0:01.00"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Image.Triggers>
</Image>
I expected the designer to preview the Opacity variations, but it actually doesn't. Am I missing something ?
I finally found the solution !
You actually need to create a separate userControl on which the animation is applied.
Once you load your userControl inside another one, the animation is playing.
My guess is that the userControl is (pre-)compiled and enables the xaml designer to play the animation.
Related
I have a control that has its margin bound to a property of my view model:
<Grid Margin="{Binding Path=Property1, Converter={StaticResource Converter1}}"></Grid>
How do I get a smooth animation between successive updates to the Margin property? I want the margin to slide for a short amount of time instead of a discrete jump. Preferably a xaml solution.
Edit:
This is different than the other questions on this site, because I would need the "From" in a thickness animation to be bound to the previous value, and "To" to be bound to the updated value. It seems like a hack to just add another property to the view model for this.
Found the solution; the animation only needs to bind to the "From" and it will animate the way I want.
<Grid Margin="{Binding Path=Property1,
NotifyOnTargetUpdated=True,
Converter={StaticResource Converter1}}">
<Grid.Triggers><EventTrigger RoutedEvent="Binding.TargetUpdated">
<BeginStoryboard><StoryBoard>
<ThicknessAnimation Storyboard.TargetProperty="Margin"
Duration="00:00:00.5"
From="{Binding Path="Property1" Converter={StaticResource Converter1}}"/>
</StoryBoard></BeginStoryboard>
</EventTrigger></Grid.Triggers>
</Grid>
You can use ThicknessAnimation:
<BeginStoryboard>
<Storyboard>
<!-- BorderThickness animates from left=1, right=1, top=1, and bottom=1 to
left=28, right=28, top=14, and bottom=14 over one second. -->
<ThicknessAnimation
Storyboard.TargetProperty="Margin"
Duration="0:0:1.5" FillBehavior="HoldEnd" From="1,1,1,1" To="28,14,28,14" />
</Storyboard>
</BeginStoryboard>
You just need to bind the properties From and To
In WPF, I have a ListBox with the list made up of UserControls. The controls are meant to navigate to different screens in the application. Each UserControl (called NavigationButton) has an icon and text. The icons are mostly combinations of multiple Path objects, so each icon is it's own UserControl, and they are being displayed using a ContentPresenter. I want to be able to animate the color of the icon depending on different states of the screen, but have tried a lot of options and have been unable to do this.
Here is a stripped down version of NavigationButton:
<DockPanel Margin="12,0,12,0">
<!-- Icon -->
<ContentPresenter x:Name="Content_Icon" Content="{Binding}" Width="20"/>
<!-- Text -->
<Grid Margin="9,0,0,0">
<TextBlock x:Name="TextBlock_Text" Text="{Binding ScreenName, Converter={StaticResource StringToStringUpperConverter}}" VerticalAlignment="Center"
FontSize="15" Foreground="#FFF2F2F2" />
</Grid>
Basically, I need to animate a property on the ContentPresenter, but don't know how to access it.
Here is the ListBox hosting the NavigationButtons:
<ListBox DockPanel.Dock="Top" ItemsSource="{Binding ScreenViewModels}"
SelectedItem="{Binding SelectedScreenViewModel}">
<ListBox.ItemTemplate>
<DataTemplate>
<my:NavigationButton/>
</DataTemplate>
</ListBox.ItemTemplate>
I have created a base UserControl (called IconBaseControl) that all of these icon UserConrols can inherit. The base control has a Brush DependencyProperty, called IconFill. The parts of the paths on the icon that can change are bound to this property:
<Path Data="<data>" Fill="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type my:IconBaseControl}}, Path=IconFill}"
I know the binding is working correctly because the colors change when I change the default color on the UserControl. Ideally I want to use a VisualStateManager, because there will be many different states. So, I have a VisualStateManager on NavigationButton, the UserControl containing the ContentPresenter that hosts the icon (all UserControls that inherit IconBaseControl), called Content_Icon. I tried something like this in one of the states:
<VisualState x:Name="Deselected">
<Storyboard>
<ColorAnimation Storyboard.TargetName="TextBlock_Text" Storyboard.TargetProperty="Foreground.Color"
To="#FF5e5e5e" Duration="0"/>
<ColorAnimation Storyboard.TargetName="Content_Icon" Storyboard.TargetProperty="IconFill"
To="#FF5e5e5e" Duration="0"/>
</Storyboard>
</VisualState>
But I get the following error:
InvalidOperationException: Cannot resolve all property references in the property path 'IconFill'. Verify that applicable objects support the properties.
I also tried binding the property of the storyboard with something like this:
Storyboard.TargetProperty="(IconBaseControl.IconFill)
But get this error:
IconBaseControl is not supported in a Windows Presentation Foundation (WPF) project.
I have also tried messing around in code behind but cannot figure out how to convert the ContentPresenter to an IconBaseControl. I figured the ContentTemplate property would be the way to go but it's Nothing.
Any suggestions on how to animate this property? Open to pretty much anything :) I'm coding in VB.Net but any C# suggestions are fine too.
Thanks in advance.
EDIT: Included code for NavigationButton
I find that creating sub-classes of WPF controls can get messy and isn't necessary unless it is a very advanced problem. In my opinion creating the IconBaseControl as a child of UserControl is overkill in your scenario.
Here's my suggestion assuming you are using MVVM: create the IconBaseControl as a normal UserControl. Just create a IconControl.xaml with IconControl.xaml.cs code behind file just like you would any other view.
Here is an example of what you would have inside IconControl:
<UserControl>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Grid.Style>
<Style>
<Style.Triggers>
<DataTrigger Binding="{Binding IsSelected}" Value="True">
<DataTrigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<ColorAnimation Storyboard.TargetProperty="(Background).(SolidColorBrush.Color)" To="#FF5e5e5e" Duration="0:0:0" />
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
<DataTrigger.ExitActions>
<BeginStoryboard>
<Storyboard>
<ColorAnimation Storyboard.TargetProperty="(Background).(SolidColorBrush.Color)" To="White" Duration="0:0:0" />
</Storyboard>
</BeginStoryboard>
</DataTrigger.ExitActions>
</DataTrigger>
</Style.Triggers>
</Style>
</Grid.Style>
<Image Source="Icon.jpeg" />
<TextBlock Text="{Binding PageName}" Grid.Column="1" />
</Grid>
</UserControl>`
Notice that the background of the surrounding grid will change based on a binding to a value called IsSelected on the DataContext. So at this point you need to create a ViewModel called IconControlViewModel.cs that has the IsSelected boolean exposed as a dependency property.
Finally the view that contains these navigation buttons:
<UserControl>
<ItemsControl ItemsSource="{Binding ListOf_IconControlViewModels}">
<ItemsControl.ItemTemplate>
<DataTemplate DataType="{x:Type IconControlViewModel}">
<local:IconView />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</UserControl>
Notice the DataTemplate that tells the ItemsControl what to render when it sees a IconControlViewModel in the ItemsSource list. This is how I would design it using the MVVM pattern. I hope this helps and let me know if you need clarification on my answer, or it's way off.
Cheers,
Eric
Hi i am trying to find some way to when a button is clicked changes the visibility of other control, like a DataGrid with a Trigger in XAML.
The button only changes the visibility of the DataGrid to Visible, it does other things in Code Behind, but this is something that i think that can be done in a Style with a Trigger.
I tried to find a solution and it seems to be possible to do but i can't understand how.
Thanks in advance.
<Button Content="Button!">
<Button.Triggers>
<EventTrigger RoutedEvent="Button.Click">
<BeginStoryboard>
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.Target="{x:Reference dataGrid}"
Storyboard.TargetProperty="Visibility">
<DiscreteObjectKeyFrame KeyTime="0:0:0"
Value="{x:Static Visibility.Visible}"/>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Button.Triggers>
</Button>
{x:Reference dataGrid} references a DataGrid with the name dataGrid, alternatively you could just use Storyboard.TargetName. You would normally use the Storyboard.Target property if you do binding or references to resources.
Just a suggestion, but how about, for something more understandable, having a Checkbox enabling/disabling the DataGrid display? This is what I usually do:
<DockPanel LastChildFill="True">
<CheckBox DockPanel.Dock="Right" VerticalAlignment="Center" x:Name="DisplayBox"
Content="Display grid" Margin="4" IsChecked="False"/>
<DataGrid Visibility="{Binding ElementName=DisplayBox, Path=IsChecked, Converter={StaticResource BoolToVisibilityConverter}}" />
</DockPanel>
And of course, you'll have to implement the appropriate converter
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>
I have a storyboard which targets an element, and binds one of its own properties to a property on another element:
<Storyboard>
<DoubleAnimation
Storyboard.TargetProperty="RenderTransform.X"
From="{Binding RelativeSource={RelativeSource AncestorType={x:Type Window}}, Path=ActualWidth}"
To="0"
Duration="0:0:5"/>
</Storyboard>
This storyboard works when the storyboard is stored in the resources of the window which holds the storyboard target. The 'From' value is correctly bound to the ActualWidth of the host Window instance.
However, I need to store the storyboard in my application level resources. From here, the storyboard does not seem to be able to target the window to determine the 'From' property. This is understandable as from inside <Application.Resources>, the binding won't be able to find an 'ancestor' of type Window.
I guess I need to be able to bind the 'From' value, relative to the target of the animation, rather than relative to the storyboard's DoubleAnimation.
Is this possible, and if so, how?
Here is the sample MainWindow.xaml:
<Window.Resources>
<!--This works : Storyboard correctly sets 'From' property to 'ActualWidth' of window-->
<Storyboard x:Key="localStoryBoard">
<DoubleAnimation
Storyboard.TargetProperty="RenderTransform.X"
From="{Binding RelativeSource={RelativeSource AncestorType={x:Type Window}}, Path=ActualWidth}"
To="0"
Duration="0:0:5"/>
</Storyboard>
</Window.Resources>
<StackPanel>
<Button
RenderTransformOrigin="0,1"
HorizontalAlignment="Left"
Content="Click me">
<Button.RenderTransform>
<TranslateTransform/>
</Button.RenderTransform>
<Button.Triggers>
<EventTrigger RoutedEvent="Button.Click">
<EventTrigger.Actions>
<BeginStoryboard Storyboard="{StaticResource centralStoryBoard}"/>
</EventTrigger.Actions>
</EventTrigger>
</Button.Triggers>
</Button>
</StackPanel>
And here is an example app.xaml:
<Application x:Class="WpfApplication3.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="MainWindow.xaml">
<Application.Resources>
<!--Storyboard doesn't work at all-->
<Storyboard x:Key="centralStoryBoard">
<DoubleAnimation
Storyboard.TargetProperty="RenderTransform.X"
From="{Binding RelativeSource={RelativeSource AncestorType={x:Type Window}}, Path=ActualWidth}"
To="0"
Duration="0:0:5"/>
</Storyboard>
</Application.Resources>
</Application>
This won't work, as the eventtrigger refers to the app.xaml version. If you change it to the local resource version, you can see it works.
The example doesn't work because when you put your storyboard to resources it has no Window ancestor. What actually RelativeSource do is search element tree backwards waiting for the node with AncestorType appear and then binds it.
When put in the Window.Resources there's actual Window back in the tree and it binds it correctly. When put to the application resources there's no Window back in the tree because it's not connected to the Window whatsoever.
If you really want to put your storyboard to the application resources you should consider giving up the idea with binding. Instead, you can check out this answer with code for a clipper, I think this is what you need - https://stackoverflow.com/a/59376318/11178539.