How to make the background color animated for a new color and vice versa without losing the original color?

So, I'm trying to create a simple animation that takes the background from the original color to the new color and vice versa.

The initial problem that I encountered was that I created a trigger on MouseDownEvent that triggered the animation, but the user can run another animation before the first one is completed. This new animation will be animated from the current hue in which it was, to a new color and vice versa. After a gradual restart of the animation during the animation, the original color is lost.

The easiest way to solve this is likely if I use a completed event for animation. However, I do not like this solution because I want my animations to be in a custom style in the resource dictionary, and not in part of the control itself. If the animation is in a custom style in the resource dictionary, then it will not have access to the code of the control itself. Is there a good way to make the animation work while keeping the separation between style and control?

Then I had a different idea. The error was caused by the fact that I was animating a new color and back with border.background.color, so if I started a new animation while the old one was on, the new animation started with any color value in which the previous animation was. But if I configure the animation to return to some saved value of the property of the original background color, then I will not have a problem, 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, for this I need to keep the original background property, and I still need to do this. I cannot use the binding because the properties in the animation must be frozen, so I tried to create a static property of the control, which is set to the original value in the event loaded with the control.

, .

xaml ? , onapplytemplate, ?

+4
3

, , , FillBehavior = Stop. , , ( , ). , , , . , , , , , , - .

                                                                                                                       

+1

, DynamicResource Freeze.

, Xaml StaticResource Xaml?

. ( Xaml, .)

StoryBoardResourceDictionary.xaml Content Copy if newer MSBuild: Compile.

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;
            }
        }
    }
}

, . , , . xaml , , .

+2

, , (, ).

<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 defined the color background as StaticResource, to use it as the background color for the grid and as a value for the animation.

In the above example, the Grid has a yellow background that animates to black and then returns to yellow when the button is pressed.

+1
source

Source: https://habr.com/ru/post/1524602/


All Articles