Раскадровки с привязанными свойствами (пользовательский элемент управления: анимировать изменение цвета)

#c# #wpf #xaml #animation

#c# #wpf #xaml #Анимация

Вопрос:

Проще говоря, у меня это в пределах ControlTemplate.Triggers условия EnterAction :

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

Но я хочу, чтобы цвет «to» ( #fe7 ) можно было настраивать. Это элемент управления, полученный из ListBox . Я могу создать DependencyProperty , но, конечно, я не могу привязать к To нему свойство the ColorAnimation , потому Storyboard что оно должно быть заморожено, и вы не можете заморозить что-либо с помощью привязок (насколько я понимаю).

Я попытался использовать a {StaticResource} внутри To , а затем заполнить ресурс в коде, когда DependencyProperty он был изменен this.Resources["ItemColour"] = newValue; , например, путем настройки. Это не сработало, возможно, очевидно, что в конце концов, это статический ресурс: новые значения свойств не были получены. DynamicResource возникла та же проблема, связанная с невозможностью зависания.

Свойство устанавливается только один раз при создании элемента управления, мне не нужно беспокоиться о том, что оно изменится в середине анимации.

Есть ли хороший способ сделать это? Должен ли я прибегать к самостоятельному поиску изменений свойств, динамически вызывая и управляя раскадровками в этот момент? Или наложение двух версий элемента управления, начального и конечного цвета, и анимация непрозрачности вместо этого? И то, и другое кажется нелепым..

Ответ №1:

Кирен,

Будет ли это служить вашей цели?

Я расширил класс сетки с именем CustomGrid и создал свойство TestProperty, значение которого при изменении изменит цвет фона сетки:

  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>
  

Будет ли это служить вашей цели? Дайте мне знать, или я неправильно понял вопрос?

Редактировать:

Смотрите этот код:

ColorAnimation к свойству не может быть привязан, как вы, наверное, догадались. Но это не значит, что вы не можете изменить его значение. Вы всегда можете получить ссылку на ColorAnimation и изменить ее на значение, и все будет хорошо. Итак, из мира привязки WPF нам нужно немного изменить и связать данные так, как мы привыкли это делать в Winforms :). В качестве примера см. Это:

Это xaml:

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

Это код, лежащий в основе:

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


}
  

Как вы можете видеть, я получаю ссылку на раскадровку и меняю ее на свойство. Очевидно, что ваш подход к StaticResource не сработает. Теперь, что вы можете сделать, это в своем DependencyProperty обратном вызове каким-то образом получить ссылку на временную шкалу, которую вы хотите анимировать, и использовать VisualTreeHelper или что-то в этом роде, а затем установить ее To свойство.

Это ваш лучший выбор.

Дайте мне знать, если это решило вашу проблему 🙂

Комментарии:

1. Это был один из моих резервных методов: программно создать раскадровку. Я задавал вопрос, чтобы узнать, есть ли другой способ добиться этого без необходимости копаться в codebehind?

2. @KierenJohnstone: Смотрите мою правку. Надеюсь, что это решит вашу проблему 🙂

3. Нет, как здесь: msdn.microsoft.com/en-us/library/ms742868.aspx вы не можете анимировать свойство внутри ControlTemplate , если вы вызываете с Begin помощью (в коде)

4. Хммм, обойти это невозможно. Все зависает. Фактически весь ResourceDictionary в controltemplate доступен только для чтения. Вы нигде не можете вносить никаких изменений. Проблема в некоторой степени связана с потокобезопасностью: (

Ответ №2:

можете ли вы поместить несколько DataTriggers, каждый из которых имеет соответствующий цвет для свойства «To»…

Комментарии:

1. Не могли бы вы объяснить это немного подробнее, пожалуйста, я не понимаю? Пользователь элемента управления сможет указать 00000000-ffffffff, то есть 1 из 4 миллиардов цветов, по одному триггеру для каждого, не так ли? 🙂

Ответ №3:

Конечно, нет.. Я понял, что вам нужен цвет A при условии A и цвет B при каком-то другом условии B….so если есть свойство с несколькими параметрами, вы можете поставить datatriggers только для этих условий…например, если работа выполнена = Красный, половина выполнена = Зеленый, как мудрый.. Если я неправильно понял проблему, пожалуйста, поправьте меня..

Кажется, у меня возник вопрос…Элемент управления UR настраивается пользователем, поэтому, что бы ни выбирал пользователь, фон элемента управления должен быть установлен на этот цвет с анимацией, верно?

Комментарии:

1. Нет, спасибо, но вы неправильно поняли. Я сказал, что хочу To , чтобы анимация была настраиваемой — привязанной к чему-то, что может быть указано пользователем. Если вы можете сказать мне, как преодолеть ограничение, заключающееся в том, что вы не можете использовать привязки (потому что раскадровки должны быть заморожены), пожалуйста, ответьте чем-нибудь, иллюстрирующим ваше решение

Ответ №4:

Оказывается, это просто невозможно.