Dear all, I've got the following problem with WPF 3.5. When accessing a dynamic resource in a storyboard, the value is wrong (seemingly the reference is not resolved) when the resource is defined in the window which contains the target control.
What am I doing wrong, and is there a right way (or at least a workaround)? Basically I want the storyboard to use the colors from dynamic resource, and I can only put those resources locally at the window level.
Example code:
<Window
x:Class="Test.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300"
MouseDoubleClick="Window_MouseDoubleClick">
<Window.Resources>
<Color x:Key="MyColor">Blue</Color>
</Window.Resources>
<Grid x:Name="outer">
<Grid.Resources>
<Storyboard x:Key="MyBoard">
<ColorAnimationUsingKeyFrames
Storyboard.TargetProperty="(Panel.Background).(SolidColorBrush.Color)">
<LinearColorKeyFrame KeyTime="0:0:0" Value="Red"/>
<LinearColorKeyFrame KeyTime="0:0:1" Value="{DynamicResource MyColor}"/>
</ColorAnimationUsingKeyFrames>
</Storyboard>
<SolidColorBrush x:Key="MyBrush" Color="{DynamicResource MyColor}"/>
</Grid.Resources>
<Grid x:Name="inner" Background="Green"/>
</Grid>
</Window>
Code-behind:
public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
}
private void Window_MouseDoubleClick(object sender, MouseButtonEventArgs e)
{
Storyboard s = (Storyboard)outer.FindResource("MyBoard");
inner.BeginStoryboard(s);
//SolidColorBrush b = (SolidColorBrush)outer.FindResource("MyBrush");
//inner.Background = b;
}
}
The problem is that the reference Value="{DynamicResource MyColor}" is not working, the value is transparent.
I tried the following:
If I move the definition of MyColor from the window resources to application resources, the code works as expected.
If I replace the storyboard start with assigning of another resource (comment out first two lines in Window_MouseDoubleClick, and uncomment the rest), the dynamic resource access works.
The behaviour in .NET 4/WPF 4 is the same.
I tried creating the storyboard from the code behind (just for test), but cannot convert the line <LinearColorKeyFrame KeyTime="0:0:1" Value="{DynamicResource MyColor}"/> into procedural code, because LinearColorKeyFrame is not FrameworkElement. Maybe this is root of the problem?
I don't know if there's a way to do it with XAML and binding, I couldn't get a similar thing working in Silverlight, but as a workaround you can create the StoryBoard and animations in code:
http://msdn.microsoft.com/en-us/library/cc189069(VS.95).aspx#procedural_code
Related
I am building a Windows WPF application that contains number of buttons.
I want to notify the user that he should load a pdf before he can press other buttons by making the load pdf button blink / vibrate if the user clicks on other places and no pdf is loaded.
For example - The exact behavior happens on Microsoft Paint if you try to click anywhere outside of the edit colors box while it is open. (see attached gif)
Does anyone have an idea ?
You can use a storyboard with a DoubleAnimation, change the drop shadow, make it go back automatically and repeat it (here 4 times).
Here is a UserControl, which you can reuse for all buttons with such effect; you only need to replace the text "Button content" by some DependencyProperty to make it versatile.
<UserControl x:Class="AnimateDropShadow"
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"
mc:Ignorable="d">
<Grid>
<Button HorizontalAlignment="Left" >
Button content
<Button.Effect>
<DropShadowEffect x:Name="warningEffect" Color="Black" BlurRadius="10" ShadowDepth="0"/>
</Button.Effect>
<Button.Triggers>
<EventTrigger RoutedEvent="Button.Click">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
Storyboard.TargetName="warningEffect"
Storyboard.TargetProperty="BlurRadius"
From="15" To="10" Duration="0:0:0.1"
AutoReverse="True" RepeatBehavior="0:0:0.4" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Button.Triggers>
</Button>
</Grid>
</UserControl>
Edit 2: Here is a link to the project.
Edit: Not sure what has happened to my Project, but it seems to have messed up big time. Getting multiple errors saying a load of my converters don't exist in the namespace, when they do!
Here I have got an instance of a Class defined in XAML:
<Application x:Class="Test_Project.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:Test_Project">
<Application.Resources>
<ResourceDictionary>
<local:runtimeObject x:Key="runtimeVariables" />
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Styles/Generic.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
</Application>
But it does exist here, as you can see below! This has just randomly suddenly messed up!
namespace Test_Project
{
/// <summary>
/// Interaction logic for App.xaml
/// </summary>
public partial class App : Application
{
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
//Startup
Window main = new MainWindow();
main.Show();
}
}
/// <summary>
/// Global values for use during application runtime
/// </summary>
public class runtimeObject : INotifyPropertyChanged
{
....
Not too sure what has gone wrong here, for some reason now I can't use a new ResourceDirectory I have made. Getting this error now:
The type or namespace name 'Styles' does not exist in the namespace
'Test_Project' (are you missing an assembly reference?)
The error is on the following line:
NotificationWindow.g.cs
using Test_Project.Styles;
NotificationWindow.xaml
<Window x:Class="Test_Project.Views.NotificationWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:Test_Project.Views"
mc:Ignorable="d"
Title="Notification" Style="{StaticResource NotificationWindow}">
<Grid RenderTransformOrigin="0,1" >
<!-- Notification area -->
<Border>
<StackPanel Margin="20">
<TextBlock>
Hello
</TextBlock>
</StackPanel>
</Border>
<!-- Animation -->
<Grid.Triggers>
<EventTrigger RoutedEvent="FrameworkElement.Loaded">
<BeginStoryboard>
<Storyboard>
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(ScaleTransform.ScaleY)">
<SplineDoubleKeyFrame KeyTime="0:0:0" Value="0"/>
<SplineDoubleKeyFrame KeyTime="0:0:0.5" Value="1"/>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Opacity)">
<SplineDoubleKeyFrame KeyTime="0:0:2" Value="1"/>
<SplineDoubleKeyFrame KeyTime="0:0:4" Value="0"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Grid.Triggers>
<Grid.RenderTransform>
<ScaleTransform ScaleY="1" />
</Grid.RenderTransform>
</Grid>
</Window>
This is my App.xaml
<Application x:Class="Test_Project.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:Test_Project">
<Application.Resources>
<ResourceDictionary>
<local:runtimeObject x:Key="runtimeVariables" />
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Styles/Generic.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
</Application>
Generic.xaml
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:Test_Project.Styles">
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Buttons.xaml" /> <!-- All Button Styles -->
<ResourceDictionary Source="Misc.xaml" /> <!-- All Misc Styles -->
<ResourceDictionary Source="Notifications.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
Here you can see my Project File Structure:
I went onto the Microsoft forums and someone helped me find the issue. When I created a ResourceDictionary it generated a local tag which has the namespace of clr-namespace:namespacehere.Styles.
This was seemed to make my new window generate a file called Window1.g.cs within it had the line using namespacehere.Styles; which was causing the problem.
#pragma checksum "..\..\..\Views\NotificationWindow.xaml" "{406ea660-64cf-4c82-b6f0-42d48172a799}" "922E7A4BDAE53DAC4A05221020498CA6"
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
using PhotoManagement.Converters;
using PhotoManagement.Styles; //Error occurs here!
using PhotoManagement.Views;
using System;
So I had to search the entire solution and remove any reference of namespacehere.Styles which seemed to cause the issue, as it is seen here:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:PhotoManagement"
xmlns:Converters="clr-namespace:PhotoManagement.Converters">
Before is had xmlns:local="clr-namespace:PhotoManagement.Styles".
So I am trying to create a simple animation that takes the background from the initial color to the new color and back.
The original issue I had is that I created a trigger on the MouseDownEvent that triggered the animation, but the user could trigger another animation before the first one finished. This new animation would animate from the current shade it was at to the new color and back. By progressively restarting the animation while the animation is going, the original color is lost.
The easiest way to solve this is probably if i use the completed event for the animation. However, I don't like this solution because I want my animations to be in a custom style in resource dictionary and not part of the control itself. If the animation is in a custom style in a resource dictionary, then it won't have access to the code behind of the control itself. Is there a good way to get an animation working while maintaining separation between the style and the control?
I then had a different idea. The error is caused because I was animating from the border.background.color to a new color and back, thus if i started a new animation while the old one was going, the new animation started from whatever color value the prior animation was in. But if I set the animation to go back to some saved property value of the original background color then I won't have the issue even if the user restarts the animation.
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:Components="clr-namespace:DaedalusGraphViewer.Components"
xmlns:Converters="clr-namespace:DaedalusGraphViewer.Components.Converters"
>
<Converters:ThicknessToLeftThicknessConverter x:Key="ThicknessToLeftThicknessConverter" />
<Style x:Key="SearchBoxListViewItemStyle" TargetType="ListViewItem">
<Setter Property="HorizontalContentAlignment" Value="Left"/>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="LightBlue" />
</Trigger>
</Style.Triggers>
</Style>
<Style x:Key="{x:Type Components:SearchBox}" TargetType="{x:Type Components:SearchBox}">
<Style.Resources>
</Style.Resources>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Components:SearchBox}">
<Border x:Name="Border"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<Grid x:Name="LayoutGrid">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<ScrollViewer
x:Name="PART_ContentHost"
Grid.Column="0"
VerticalAlignment="Center"
/>
<Label
x:Name="DefaultTextLabel"
Grid.Column="0"
Foreground="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=TextColor}"
Content="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=LabelText}"
VerticalAlignment="Center"
FontStyle="Italic"
/>
<Popup x:Name="RecentSearchesPopup"
IsOpen="False"
>
<ListView
x:Name="PreviousSearchesListView"
ListView.ItemContainerStyle="{StaticResource SearchBoxListViewItemStyle}"
>
</ListView>
</Popup>
<Border
x:Name="PreviousSearchesBorder"
Grid.Column="2"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Background="LightGray"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=BorderThickness,
Converter={StaticResource ThicknessToLeftThicknessConverter}}"
>
<Image
x:Name="PreviousSearchesIcon"
ToolTip="Previous Searches"
Width="15"
Height="15"
Stretch="Uniform"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Source="pack://application:,,,/DaedalusGraphViewer;component/Images/Previous.png"
/>
</Border>
</Grid>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="HasText" Value="True">
<Setter Property="Visibility" TargetName="DefaultTextLabel" Value="Hidden" />
</Trigger>
<Trigger
SourceName="DefaultTextLabel"
Property="IsMouseOver"
Value="True"
>
<Setter Property="Cursor" Value="IBeam" />
</Trigger>
<!--<EventTrigger RoutedEvent="Mouse.MouseDown" SourceName="PreviousSearchesBorder">
<BeginStoryboard>
<Storyboard>
<ColorAnimation
AutoReverse="True"
Duration="0:0:0.2"
Storyboard.TargetName="PreviousSearchesBorder"
Storyboard.TargetProperty="(Border.Background).Color"
To="Black"
/>
</Storyboard>
</BeginStoryboard>
</EventTrigger>-->
<Trigger Property="IsPopupOpening" Value="True">
<Trigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<ColorAnimationUsingKeyFrames
Storyboard.TargetName="PreviousSearchesBorder"
Storyboard.TargetProperty="(Border.Background).Color"
>
<LinearColorKeyFrame KeyTime="0:0:0.0" Value="{x:Static Components:SearchBox.DefaultRecentSearchesButtonColor}" />
<LinearColorKeyFrame KeyTime="0:0:0.2" Value="Black" />
<LinearColorKeyFrame KeyTime="0:0:0.4" Value="{x:Static Components:SearchBox.DefaultRecentSearchesButtonColor}" />
</ColorAnimationUsingKeyFrames>
<!--<ColorAnimation
AutoReverse="True"
Duration="0:0:0.2"
Storyboard.TargetName="PreviousSearchesBorder"
Storyboard.TargetProperty="(Border.Background).Color"
To="Black"
/>-->
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
</Trigger>
However, in order to do this I need to store the original background property and I have yet to get that working. I cannot using binding because properties in Animations must be freezeable, so I tried creating a static property on the control that gets set to the original value on the control's loaded event.
I set the color to the background color in the code behind, but the style does not reflect that property.
Is my static reference in the xaml correct? if so, then isn't onapplytemplate when the style should load the color from the static reference?
Well, you can't use a DynamicResource without getting a Freeze error.
What if you loaded the Xaml file at runtime and added the StaticResource to the Xaml file?
Here is an example. (I use some quick and dirty parsing of the Xaml file, but it works for the proof of concept.)
Change the properties of the StoryBoardResourceDictionary.xaml to Content and Copy if newer and remove the MSBuild:Compile setting.
StoryBoardResourceDictionary.xaml
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Style x:Key="WindowWithTrigger" TargetType="Window">
<Style.Triggers>
<EventTrigger RoutedEvent="Mouse.MouseDown">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard>
<ColorAnimationUsingKeyFrames Storyboard.TargetProperty="(Panel.Background).(SolidColorBrush.Color)" >
<EasingColorKeyFrame KeyTime="0:0:2" Value="White"/>
<!-- OriginalBackground is added at runtime -->
<EasingColorKeyFrame KeyTime="0:0:4" Value="{StaticResource OriginalBackground}"/> <!-- Load at runtime -->
</ColorAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
</Style.Triggers>
</Style>
</ResourceDictionary>
MainWindow.xaml
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="BackgroundAnimationBlend.MainWindow"
x:Name="Window"
Title="MainWindow"
Width="640" Height="480"
Style="{DynamicResource WindowWithTrigger}"
Background="DarkBlue"> <!--Change background to whatever color you want -->
</Window>
MainWindow.xaml.cs
using System.IO;
using System.Text;
using System.Windows;
using System.Windows.Markup;
namespace BackgroundAnimationBlend
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
var rd2 = LoadFromFile();
this.Resources.MergedDictionaries.Add(rd2);
}
public ResourceDictionary LoadFromFile()
{
const string file = "Styles/StoryBoardResourceDictionary.xaml";
if (!File.Exists(file))
return null;
using (var fs = new StreamReader(file))
{
string xaml = string.Empty;
string line;
bool replaced = false;
while ((line = fs.ReadLine()) != null)
{
if (!replaced)
{
if (line.Contains("OriginalBackground"))
{
xaml += string.Format("<Color x:Key=\"OriginalBackground\">{0}</Color>", Background);
replaced = true;
continue;
}
}
xaml += line;
}
// Read in an EnhancedResourceDictionary File or preferably an GlobalizationResourceDictionary file
return XamlReader.Load(new MemoryStream(Encoding.UTF8.GetBytes(xaml))) as ResourceDictionary;
}
}
}
}
I have no idea how to scale this right now. So maybe it is a crazy idea. But loading the style at runtime and injecting the current background as a xaml string into the style before loading it is the only idea I had that worked.
I have made a small example to illustrate how you can solve your problem (by what i have understood).
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<Color x:Key="background">yellow</Color>
<SolidColorBrush x:Key="backgroundBrush" Color="{StaticResource background}"/>
<Storyboard x:Key="Storyboard1">
<ColorAnimationUsingKeyFrames Storyboard.TargetProperty="(Panel.Background).(SolidColorBrush.Color)" Storyboard.TargetName="grid">
<SplineColorKeyFrame KeyTime="0:0:0.3" Value="Black"/>
<SplineColorKeyFrame KeyTime="0:0:0.6" Value="{StaticResource background}"/>
</ColorAnimationUsingKeyFrames>
</Storyboard>
</Window.Resources>
<Grid x:Name="grid" Background="{StaticResource backgroundBrush}">
<Button x:Name="button" Content="Button" HorizontalAlignment="Left" VerticalAlignment="Top" Width="75" RenderTransformOrigin="0.5,0.5">
<Button.Triggers>
<EventTrigger RoutedEvent="Button.Click">
<BeginStoryboard Storyboard="{StaticResource Storyboard1}" Name="Storyboard1"/>
</EventTrigger>
</Button.Triggers>
</Button>
</Grid>
I have defined a Color background as StaticResource to use it as Background-Color for the Grid and as Value for the Animation.
In the example above the Grid has a yellow background, that gets animated to black and then back to yellow when the button is clicked.
So all I ended up doing was using FillBehavior = Stop. I was new to animations so I didn't know how to prevent the reactivation of the animation easily without access to the completed event (which would have to be attached in the control, thus defeating the purpose of having a style with animations in a separate resource file). Regardless, I'm giving the bounty to rhyous because his answer actually does solve my problem as well, though in a more difficult manner. I knew that what i wanted to do had to be simple because there was no way that no one had wanted to animate a color and back from a style, yet I couldn't find any Stack Overflow questions on the issue
I have a window with a number or Dynamic Resources for colors/brushes on it.
For example this; EXAMPLE 1 DOES NOT UPDATE "DynamicResource ColFancyMed"
<Rectangle x:Name="dbBarPeekOutRect1" Margin="3,10,10,10" >
<Rectangle.Fill>
<SolidColorBrush Color="{DynamicResource ColFancyMed}" />
</Rectangle.Fill>
</Rectangle>
When my App starts the Resource file is read and the right color is shown.
These colors are however themed and so I have a number of resource dictionaries with these resource keys in them. Thus I change the resource dictionary like this
Application.Current.Resources.MergedDictionaries.RemoveAt(0)
Application.Current.Resources.MergedDictionaries.Insert(0, dict)
This works elsewhere but not on the above. The funny thing is if I use the following. The only difference I can see is one is a Color and the other is a SolidColorBrush.
EXAMPLE 2 DOES UPDATE "DynamicResource ColFancyMed"
<Rectangle x:Name="dbBarPeekOutRect1" Margin="3,10,10,10" Fill="{DynamicResource ColFancyMed}"/>
Then the color changes.
So why does example 1 NOT work and example 2 work?
Similarly another place where it does not work is in the for example;
<Storyboard x:Key="dbBarPeekOutHighlight">
<ColorAnimationUsingKeyFrames Storyboard.TargetProperty="(Shape.Fill).(SolidColorBrush.Color)" Storyboard.TargetName="dbBarPeekOutRect1">
<EasingColorKeyFrame KeyTime="0" Value="{DynamicResource ColFancyMed}"/>
<EasingColorKeyFrame KeyTime="0:0:0.2" Value="#FFF2F6F9"/>
</ColorAnimationUsingKeyFrames>
<ColorAnimationUsingKeyFrames Storyboard.TargetProperty="(Shape.Fill).(SolidColorBrush.Color)" Storyboard.TargetName="dbBarPeekOutRect2">
<EasingColorKeyFrame KeyTime="0" Value="{DynamicResource ColFancyMed}"/>
<EasingColorKeyFrame KeyTime="0:0:0.2" Value="#FFF2F6F9"/>
</ColorAnimationUsingKeyFrames>
</Storyboard>
Any help would be appreciated.
Regarding the last example with the storyboard, as MSDN states here
You can't use dynamic resource references or data binding expressions to set Storyboard or animation property values. That's because everything inside a Style must be thread-safe, and the timing system must Freeze Storyboard objects to make them thread-safe. A Storyboard cannot be frozen if it or its child timelines contain dynamic resource references or data binding expressions. For more information about freezing and other Freezable features, see the Freezable Objects Overview.
Regarding the first example I'm not sure if the problem is that you're instantiating a SolidColorBrush object instead of binding directly to your resource.
For me, this example works:
<Grid>
<Rectangle x:Name="dbBarPeekOutRect1" Width="100" Height="100" Margin="3,10,10,10" >
<Rectangle.Fill>
<SolidColorBrush Color="{DynamicResource MyColor}" />
</Rectangle.Fill>
</Rectangle>
<Rectangle x:Name="dbBarPeekOutRect2" Width="100" Height="100" HorizontalAlignment="Left" Fill="{DynamicResource MyColor2}"/>
<Button Name="ChangeResource" Content="ChangeResource" Width="100" Height="30" VerticalAlignment="Bottom" Click="ChangeResource_Click" />
</Grid>
Handler of ChangeResource Button:
private void ChangeResource_Click(object sender, RoutedEventArgs e)
{
Color MyCodeColor = Colors.BlanchedAlmond;
SolidColorBrush MyBrush = Brushes.Aquamarine;
// Set the new value
Application.Current.Resources["MyColor"] = MyCodeColor;
Application.Current.Resources["MyColor2"] = MyBrush;
}
I put the color in the resources App.xaml file:
<Application.Resources>
<Color x:Key="MyColor">#D8C13E</Color>
<SolidColorBrush x:Key="MyColor2" Color="Green" />
</Application.Resources>
As for the animation... If I'm not mistaken, when the animation is used, an WPF Animation will lock the target properties value as long as the animation is still active. Therefore DynamicResource transformed into StaticResource. As example: also when you use the property Opacity in animation, the code does not have access.
I'm having trouble getting a storyboard value to bind to my viewmodel. I've tried many varieties of binding xaml, with no luck. The high level goal is to be able for the ViewModel to change the start and end of an animation's trajectory - seems like a common requirement, but haven't been able to find any examples of it. Many people say "In MVVM you should never try to access the storyboard from the ViewModel" which seems like horeshit if you need to change the start and end points of the animation on the fly. In any case, I've shown my first, naive example here:
<UserControl
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:FishTank" x:Class="FishTank.FishTankControlView"
mc:Ignorable="d"
d:DesignHeight="100" d:DesignWidth="100" >
<UserControl.Resources>
<Storyboard x:Key="Storyboard1">
<DoubleAnimationUsingKeyFrames x:Name="xTransform" Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[3].(TranslateTransform.X)" Storyboard.TargetName="image">
<SplineDoubleKeyFrame KeyTime="0" Value="-155"/>
<SplineDoubleKeyFrame KeyTime="0:0:4.5" Value="521"/>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames x:Name="yTransform" Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[3].(TranslateTransform.Y)" Storyboard.TargetName="image">
<SplineDoubleKeyFrame KeyTime="0" Value="{Binding YPos1}"/>
<SplineDoubleKeyFrame KeyTime="0:0:4.5" Value="{Binding YPos2}"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</UserControl.Resources>
<UserControl.DataContext>
<local:FishTankControlViewModel/>
</UserControl.DataContext>
<UserControl.Triggers>
<EventTrigger RoutedEvent="FrameworkElement.Loaded">
<BeginStoryboard Storyboard="{DynamicResource Storyboard1}"/>
</EventTrigger>
</UserControl.Triggers>
<Grid Background="Transparent">
<Image x:Name="image" Width="100" Height="100" Source="pack://siteoforigin:,,,/Resources/Fish orange_right.png" RenderTransformOrigin="0.5,0.5">
<Image.RenderTransform>
<TransformGroup>
<ScaleTransform/>
<SkewTransform/>
<RotateTransform/>
<TranslateTransform/>
</TransformGroup>
</Image.RenderTransform>
</Image>
</Grid>
I want to have Ypos1 and Ypos2 bound to the start and end points of the Y transformation. I've tried various variations using RelativeSource and FindAncestor, but it's all pretty much over my head. I would like a solution that allows me to stick with the 3.5 framework if possible.
I tried changing the "StaticResource Storyboard1" to "DynamicResource Storyboard1" with no luck.
Note - As a sanity check, I confirmed I am able to bind normal controls like buttons and textblocks to these two properties, Ypos1 and Ypos2, so I'm pretty sure the basic plumbing is working...
Thanks much,
Randy
You can't bind those because they need to be freezable, pretty sure the framework told you so as well.
If anything you can completely recreate or modify the animation with new values, using a ValueConverter or a subclass that encapsulates the animation being modified.