Как анимировать свойство переднего плана нескольких элементов «Run» в текстовом блоке в UWP?

#c# #uwp

#c# #uwp

Вопрос:

У меня есть этот код. Это всего лишь пример. Я хочу сделать это с помощью кода. Как анимировать свойство переднего плана нескольких элементов «Run» в текстовом блоке?

 <Page
    x:Class="AnimationTest.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:local="using:AnimationTest"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"
    mc:Ignorable="d">

    <Grid>

        <TextBlock
            x:Name="_textBlockElement"
            HorizontalAlignment="Center"
            VerticalAlignment="Center"
            FontSize="72"><Run x:Name="_run1" Text="Hel" /><Run Text="lo" />
            <TextBlock.Triggers>
                <EventTrigger>
                    <BeginStoryboard>
                        <Storyboard x:Name="ColorStoryboard">
                            <ColorAnimation
                                AutoReverse="True"
                                RepeatBehavior="Forever"
                                Storyboard.TargetName="_textBlockElement"
                                Storyboard.TargetProperty="(TextBlock.Foreground).(SolidColorBrush.Color)"
                                To="Red"
                                Duration="0:0:2" />
                        </Storyboard>
                    </BeginStoryboard>
                </EventTrigger>
            </TextBlock.Triggers>
        </TextBlock>

    </Grid>
</Page>
  

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

1. Во время тестирования <Run x:Name="_run1" Text="Hel" /><Run Text="lo" /> можно было бы добавить анимацию одновременно. Не могли бы вы рассказать, какую функцию вы хотите реализовать?

2. @NicoZhu-MSFT, есть текстовый блок, который состоит из нескольких элементов «Run». Каждый элемент окрашен в свой собственный цвет. Мне нужно, чтобы все элементы Run становились красными при наведении курсора мыши на текстовый блок. Когда курсор мыши удаляется от текстового блока, все элементы Run возвращаются к своим предыдущим цветам. Я сделаю это из кода. Код XAML — это просто пример.

Ответ №1:

Оке, так что это заняло довольно много времени, но оказалось вполне выполнимым.

Ключ в том, чтобы создать две раскадровки в коде с правильной анимацией, а затем добавить эти раскадровки к ресурсам любого Run родительского элемента.

Давайте начнем с XAML кода, который довольно прост:

 <Grid>
    <TextBlock x:Name="TestBlock"
               HorizontalAlignment="Center" VerticalAlignment="Center"
               PointerEntered="TestBlock_PointerEntered"
               PointerExited="TestBlock_PointerExited">
        <Run x:Name="Run1" Text="Test1" Foreground="Blue"/>
        <Run x:Name="Run2" Text="Test2" Foreground="Green"/>
        <!-- ... -->
    </TextBlock>
</Grid>
  

Для простоты я уже определил имена и передние планы Run ‘s.

Теперь нам нужно определить раскадровки и анимации в коде.
Я решил сделать это в конструкторе (после InitializeComponent() !). Теоретически вы должны иметь возможность также вставить этот код в Page_Loaded событие.

 public MainPage()
{
    InitializeComponent();
    SetupStoryBoards();
}

void SetupStoryBoards()
{
    // Define duration and storyboards to red and original color
    var duration = new Duration(TimeSpan.FromSeconds(1));

    var toRedStory = new Storyboard { Duration = duration };
    // completed events can be subscribed to, to register when animation is done
    //toRedStory.Completed  = Story_Completed;

    var toOriginalStory = new Storyboard { Duration = duration };
    //toOriginalStory.Completed  = ToOriginalStory_Completed;

    foreach (Run r in TestBlock.Inlines)
    {
        // Filter out any inlines that are not a named Run
        if (string.IsNullOrEmpty(r.Name))
            continue;

        // Define the animations
        var toRedAnim = new ColorAnimation
        {
            Duration = duration,
            To = Colors.Red,
            EnableDependentAnimation = true
        };
        var toOriginalAnim = new ColorAnimation
        {
            Duration = duration,
            To = (r.Foreground as SolidColorBrush).Color, // Causes animation to go back to original foreground color of Run
            EnableDependentAnimation = true
        };

        // Add animations to the storyboards and associate animations with the Run
        toRedStory.Children.Add(toRedAnim);
        toOriginalStory.Children.Add(toOriginalAnim);

        Storyboard.SetTargetName(toRedAnim, r.Name);
        Storyboard.SetTargetName(toOriginalAnim, r.Name);

        Storyboard.SetTargetProperty(toRedAnim, "(Run.Foreground).(SolidColorBrush.Color)");
        Storyboard.SetTargetProperty(toOriginalAnim, "(Run.Foreground).(SolidColorBrush.Color)");
    }

    // Add the storyboards to the resources of any parent of the Run's for easy retrieval later and to make the animations find the Run's
    // I choose the resources of the textblock that contains the Run's
    TestBlock.Resources.Add("toRedStory", toRedStory);
    TestBlock.Resources.Add("toOriginalStory", toOriginalStory);
}
  

Теперь, чтобы выполнить анимацию, мы добавляем PointerEntered обработчики PointerExited событий и и запускаем там правильные раскадровки:

 private void TextBlock_PointerEntered(object sender, PointerRoutedEventArgs e)
{
    var story = TestBlock.Resources["toRedStory"] as Storyboard;
    story.Begin();
}

private void TextBlock_PointerExited(object sender, PointerRoutedEventArgs e)
{
    var story = TestBlock.Resources["toOriginalStory"] as Storyboard;
    story.Begin();
}
  

Вы должны иметь возможность расширять это везде, где это необходимо, однако я обнаружил, что для этого EnableDependentAnimation должно быть установлено true значение, поскольку в противном случае оно не будет работать.