SolidColorBrushes as Dynamic Resources are not updating - c#

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.

Related

UWP TextBox Background when Focused

For some reason there's no easy way to change focused background of TextBox from the default White color.
The only way it works (I need it to be dark-ish or transparent) is to create custom textbox, paste bazzillion lines of code (from here) and then edit TWO lines:
<VisualState x:Name="Focused">
<Storyboard>
...
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="BackgroundElement"
Storyboard.TargetProperty="Background">
<DiscreteObjectKeyFrame KeyTime="0" Value="#000000" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="BackgroundElement" Soryboard.TargetProperty="Opacity">
<DiscreteObjectKeyFrame KeyTime="0" Value="0.1" />
</ObjectAnimationUsingKeyFrames>
My question is: is there a better way to do it? Is all the other code necessary (~240 lines)?
Thank you.
Do this in your App.xaml file:
<Application>
<Application.Resources>
<SolidColorBrush x:Key="TextControlBackgroundFocused" Color="Black" Opacity="0.2"/>
<SolidColorBrush x:Key="TextControlForegroundFocused" Color="White"/>
<SolidColorBrush x:Key="TextControlBorderBrushFocused" Color="White" Opacity="0.2"/>
</Application.Resources>
</Application>
This will overwrite the default colors with your own custom colors for every TextBox in your project. If you want to apply the appearance to only some of your TextBoxes, define it locally for each TextBox:
<TextBox>
<TextBox.Resources>
Put brushes here
</TextBox.Resources>
</TextBox>
It would be easier to create a style and then apply it. At design time you can use the Document Outline pane in Visual Studio and right-click the TextBox. Then choose the Edit Template -> Edit Copy. Then modify that style in the same way you have done in your question.

Silverlight - Style ALL Image Buttons to Change on MouseOver

I'm having a really hard time finding a way to do the following...
I have my "Image button style," and it is applied to every button in my Silverlight app. Is there any way to make a blanket VisualStateManager to change the image on MouseOver, that will work for every button? I have a couple ideas, but I'm not sure if they can be implemented...
Let's say my button image paths are consistent:
image1.png
image2.png
and
image1 - hover.png
image2 - hover.png
Is there a way to change the path of the image to append " - hover"? I thought about using an IValueConverter for this, but wasn't sure how to access the control state...
An alternative idea I had was if there was a way to accomplish this:
<Button>
<Image Source="../Images/image1.png" Width="70"/>
<Image Source="../Images/image1 - hover.png" Width="70"/>
</Button>
Have two contents (an array of content?) and on Normal state, set only the first content opacity to 1, and the rest to 0. Then on MouseOver, switch the opacities.
Are any of these solutions feasible, and how can they be implemented?
Thanks
Edit: I know I can make custom styles for each button that switch out their images, but I would like a blanket style that I can apply to all buttons.
You may (ab)use the Tag property for your purpose and create a ControlTemplate with two Image controls with a BitmapImage that binds its UriSource property to either the Content or the Tag property respectively:
<Style TargetType="Button">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Grid>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup Name="CommonStates">
<VisualState Name="Normal"/>
<VisualState Name="MouseOver">
<Storyboard>
<DoubleAnimation
Storyboard.TargetName="image1"
Storyboard.TargetProperty="Opacity"
To="0" Duration="0:0:0.1"/>
<DoubleAnimation
Storyboard.TargetName="image2"
Storyboard.TargetProperty="Opacity"
To="1" Duration="0:0:0.1"/>
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Image x:Name="image1">
<Image.Source>
<BitmapImage UriSource="{Binding Content,
RelativeSource={RelativeSource Mode=TemplatedParent}}"/>
</Image.Source>
</Image>
<Image x:Name="image2" Opacity="0">
<Image.Source>
<BitmapImage UriSource="{Binding Tag,
RelativeSource={RelativeSource Mode=TemplatedParent}}"/>
</Image.Source>
</Image>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Now you may declare a Button like this:
<Button Content="../Images/image1.png" Tag="../Images/image1_hover.png"/>

Trouble binding storyboard values to viewmodel

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.

Update page layout before Thread.Sleep()

I have a TextBlock on my page with Text value null (""). When I click a button I want to change the Text value for this TextBlock, pause half a second and then move the TextBlock one pixel at a time to a certain point.
I tried using Thread.Sleep(), but so far, I have a problem. I click the button, the UI thread pauses for half a second, then the TextBlock suddenly appears and starts moving. I want it to appear as soon as I click the button.
P.S.: I know Thread.Sleep() doesn't work. I am willing to use anything that works.
Storyboards and animations are the preferred mechanism for moving items on the screen. For one thing, they are optimized to work with the phones threading model. For another, putting your UI thread to sleep is a bad idea as you are making a non responsive application.
Here's a quick example of how to move a texblock with a story board.
The UI elements.
<Grid
x:Name="ContentPanel"
Grid.Row="1"
Margin="12,0,12,0">
<TextBlock
Margin='79,263,177,307'
Name='textBlock1'
Text='TextBlock'
RenderTransformOrigin="0.5,0.5">
<TextBlock.RenderTransform>
<CompositeTransform />
</TextBlock.RenderTransform>
</TextBlock>
<Button
Content="Button"
Height="80"
Margin="116,0,188,144"
VerticalAlignment="Bottom"
Click='Button_Click' />
</Grid>
The storyboard, defined in the page resources section.
<phone:PhoneApplicationPage.Resources>
<Storyboard
x:Name="MoveTextBlockStoryboard">
<DoubleAnimationUsingKeyFrames
Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.TranslateX)"
Storyboard.TargetName="textBlock1">
<EasingDoubleKeyFrame
KeyTime="0"
Value="0" />
<EasingDoubleKeyFrame
KeyTime="0:0:1.1"
Value="120" />
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames
Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.TranslateY)"
Storyboard.TargetName="textBlock1">
<EasingDoubleKeyFrame
KeyTime="0"
Value="0" />
<EasingDoubleKeyFrame
KeyTime="0:0:1.1"
Value="-105" />
</DoubleAnimationUsingKeyFrames>
</Storyboard>
The code that changes the text and starts the storyboard.
private void Button_Click(object sender, RoutedEventArgs e) {
textBlock1.Text = "new text";
MoveTextBlockStoryboard.Begin();
}
Try using a storyboard instead of writing code to do this. I think it will perform better for you than a manual approach.

Dynamic resource access fails in storyboard

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

Categories