C# 具有绑定属性的故事板(自定义控件:设置颜色更改动画)

C# 具有绑定属性的故事板(自定义控件:设置颜色更改动画),c#,wpf,xaml,animation,C#,Wpf,Xaml,Animation,简单地说,我在一个ControlTemplate.Triggersconditionentreaction中有这个: <ColorAnimation To="#fe7" Storyboard.TargetProperty="Background.Color" Duration="00:00:00.1" Storyboard.TargetName="brd"/> 但是我希望“to”颜色(#fe7)可以定制。这是从列表框派生的控件。我可以创建一个dependencProperty,

简单地说,我在一个
ControlTemplate.Triggers
condition
entreaction
中有这个:

<ColorAnimation To="#fe7" Storyboard.TargetProperty="Background.Color" Duration="00:00:00.1" Storyboard.TargetName="brd"/>

但是我希望“to”颜色(
#fe7
)可以定制。这是从
列表框
派生的控件。我可以创建一个
dependencProperty
,但是当然,我不能将
彩色动画的
属性绑定到它,因为
情节提要
必须被冻结,并且不能用绑定来冻结某些内容(据我所知)

我尝试在
中使用
{StaticResource}
,然后通过设置
this.Resources[“ItemColour”]=newValue,在
DependencyProperty
更改时在代码中填充资源例如。这显然不起作用,毕竟它是一个静态资源:没有拾取新的属性值
DynamicSource
给出了与无法冻结相关的相同问题

该属性在创建控件时只设置一次,我不必担心它会在动画中期更改


有什么好办法吗?我是否必须自己寻找属性更改,动态地调用和管理情节提要?还是覆盖两个版本的控件,开始和结束颜色,并设置不透明度动画?这两种方法看起来都很可笑。

您可以放置多个数据触发器,每个数据触发器的“To”属性都有各自的颜色。

当然不能。。 我所理解的是,你想要条件A上的颜色A和其他条件B上的颜色B…因此,如果有一个属性具有多个选项,你可以只为这些条件放置datatriggers…就像如果作业完成=红色,一半完成=绿色一样。。 如果我误解了这个问题,请纠正我

我想我有你的问题了…你的控件是用户可配置的,所以用户选择什么,控件的背景需要设置为动画的颜色,对吗?

Kieren

这对你有用吗

我扩展了名为CustomGrid的Grid类,并创建了一个TestProperty,其值在更改时将更改Grid的背景颜色:

 public class CustomGrid : Grid
    {
        public bool Test
        {
            get
            {
                return (bool)GetValue(TestProperty);
            }
            set
            {
                SetValue(TestProperty, value);
            }
        }
        public static readonly DependencyProperty TestProperty =
            DependencyProperty.Register("Test", typeof(bool), typeof(CustomGrid),
                new PropertyMetadata(new PropertyChangedCallback
                    ((obj, propChanged) =>
                    {

                        CustomGrid control = obj as CustomGrid;
                        if (control != null)
                        {
                            Storyboard sb = new Storyboard() { Duration = new Duration(TimeSpan.FromMilliseconds(500)) };

                            Random rand = new Random();
                            Color col = new Color()
                            {
                                A = 100,
                                R = (byte)(rand.Next() % 255),
                                G = (byte)(rand.Next() % 255),
                                B = (byte)(rand.Next() % 255)
                            };


                            ColorAnimation colAnim = new ColorAnimation();

                            colAnim.To = col;
                            colAnim.Duration = new Duration(TimeSpan.FromMilliseconds(500));


                            sb.Children.Add(colAnim);
                            Storyboard.SetTarget(colAnim, control);
                            Storyboard.SetTargetProperty(colAnim, new PropertyPath("(Panel.Background).(SolidColorBrush.Color)"));

                            sb.Begin();

                        }
                    }
                )));
    }
这是更改颜色的按钮单击事件:

 private void btnClick_Click(object sender, RoutedEventArgs e)
        {
            gridCustom.Test = (gridCustom.Test == true) ? false : true;
        }
我正在更改网格的背景色,因为我没有您的列表框

最后是xaml:

 <Grid x:Name="grid" Background="White">
        <local:CustomGrid x:Name="gridCustom" Background="Pink" Height="100" Margin="104,109,112,102" >

        </local:CustomGrid>
        <Button Content="Click Me" x:Name="btnClick" Height="45" HorizontalAlignment="Left" Margin="104,12,0,0"  VerticalAlignment="Top" Width="145" Click="btnClick_Click" />
    </Grid>
<Window
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

        xmlns:Microsoft_Windows_Themes="clr-namespace:Microsoft.Windows.Themes;assembly=PresentationFramework.Aero" x:Class="ControlTemplateTriggers.MainWindow"
        Title="MainWindow" Height="350" Width="525">
    <Window.Resources>

        <Storyboard x:Key="Storyboard">
            <ColorAnimation From="Black" To="Red" Duration="00:00:00.500" Storyboard.TargetProperty="(Panel.Background).(SolidColorBrush.Color)" Storyboard.TargetName="gridCustom" />
        </Storyboard>
    </Window.Resources>

    <Grid x:Name="grid" Background="White">
        <Grid x:Name="gridCustom" Background="Pink" Height="100" Margin="104,109,112,102" />

        <Button Content="Click Me" x:Name="btnClick" Height="45" HorizontalAlignment="Left" Margin="104,12,0,0"  VerticalAlignment="Top" Width="145" Click="btnClick_Click" />
    </Grid>
</Window>
正如你所看到的,我得到了对故事板的引用,并将其更改为属性。你的静态资源方法显然行不通。现在,您可以做的是,在
dependencProperty
回调中,以某种方式获取对要设置动画的时间线的引用,并使用VisualTreeHelper或其他方法,然后将其
设置为
属性

这是你最好的选择


让我知道这是否解决了您的问题:)

事实证明这根本不可能。

请您再解释一下,我不明白?控件的用户将能够指定00000000-ffffffff,即40亿种颜色中的1种,每种颜色一个触发器,当然不是:)不,谢谢,但你误解了。我说我希望动画的
To
是可定制的-绑定到用户可以指定的东西上。如果你能告诉我如何克服不能使用绑定的限制(因为故事板必须被冻结),那么请用一些说明你的解决方案的东西来回应。这是我的一种退步技巧:通过编程创建故事板。我问这个问题是想看看是否有其他方法可以实现这一点,而不必在codebehind中进行黑客攻击?@KierenJohnstone:参见我的编辑。希望它能解决您的问题:)不,正如这里所说的:如果您使用
Begin
(在代码中)调用
ControlTemplate
,则无法在
ControlTemplate
中设置属性的动画。一切都冻结了。事实上,controltemplate中的整个ResourceDictionary是只读的。您不能在任何地方进行任何更改。该问题在某种程度上与线程安全相关:(
using System.Windows;
using System.Windows.Media.Animation;
using System.Windows.Media;
using System;

namespace Sample    {

    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            this.DataContext = this;

        }

        private void btnClick_Click(object sender, RoutedEventArgs e)
        {
            Storyboard sb = this.Resources["Storyboard"] as Storyboard;
            if (sb != null)
            {
                ColorAnimation frame = sb.Children[0] as ColorAnimation;
                Random rand = new Random();
                Color col = new Color()
                              {
                                  A = 100,
                                  R = (byte)(rand.Next() % 255),
                                  G = (byte)(rand.Next() % 255),
                                  B = (byte)(rand.Next() % 255)
                              };
                frame.To = col;
                sb.Begin();
            }
        }
    }


}