c# - 如何在不丢失原始颜色轨迹的情况下使背景颜色动画为新颜色并返回?

标签 c# wpf xaml animation

所以我正在尝试创建一个简单的动画,使背景从初始颜色变为新颜色并返回。

我遇到的最初问题是,我在触发动画的 MouseDownEvent 上创建了一个触发器,但用户可以在第一个动画完成之前触发另一个动画。这个新动画将从当前的阴影动画到新的颜色并返回。通过在动画进行时逐渐重新启动动画,原始颜色会丢失。

解决这个问题的最简单方法可能是我将完成的事件用于动画。但是,我不喜欢这个解决方案,因为我希望我的动画在资源字典中采用自定义样式,而不是控件本身的一部分。如果动画是资源字典中的自定义样式,那么它将无法访问控件本身的代码。有没有一种好的方法可以让动画工作同时保持样式和控件之间的分离?

然后我有了不同的想法。错误是因为我从 border.background.color 到新颜色再返回动画,因此如果我在旧动画运行时开始新动画,则新动画从先前动画所在的任何颜色值开始。但是,如果我将动画设置为返回原始背景颜色的某些已保存属性值,那么即使用户重新启动动画,我也不会有问题。

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

但是,为了做到这一点,我需要存储原始背景属性,但我还没有让它工作。我不能使用绑定(bind),因为动画中的属性必须是可卡住的,所以我尝试在控件上创建一个静态属性,该属性在控件的加载事件中设置为原始值。

我在后面的代码中将颜色设置为背景色,但样式并未反射(reflect)该属性。

我在 xaml 中的静态引用是否正确?如果是这样,那么当样式应该从静态引用加载颜色时不是 onapplytemplate 吗?

最佳答案

好吧,你不能在没有卡住错误的情况下使用 DynamicResource。

如果您在运行时加载 Xaml 文件并将 StaticResource 添加到 Xaml 文件会怎样?

这是一个例子。 (我对 Xaml 文件进行了一些快速而肮脏的解析,但它适用于概念验证。)

将 StoryBoardResourceDictionary.xaml 的属性更改为 Content 和 Copy(如果较新)并删除 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 字符串注入(inject)样式是我唯一可行的想法。

关于c# - 如何在不丢失原始颜色轨迹的情况下使背景颜色动画为新颜色并返回?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21467242/

相关文章:

c# - 使用从 WinForms 到 WPF 的放大 API

c# - 查找文本 block /文本的高度

c# - EF 5 派生类无法访问部分类的属性

c# - linq 作为列名的数据集问题

c# - LiveCharts2将不断变化的数据绑定(bind)到图表上

c# - 如何在我的 View 模型中访问日历控件中的选定日期?

c# - UWP MediaElement 随机崩溃

c# - Entity Framework Core 中的自引用多对多关系

c# - 命名空间 'Nmo' 中不存在类型或命名空间名称 'Microsoft.SqlServer.Management'

c# - 具有依赖属性的 ContentPresenter 和 Datatemplates