There are dozens of projects designed and animated by WPF

There are dozens of projects designed and animated by WPF

This is a WPF project to create and collect some fun designs and animations. There are currently dozens of demos, and some demos have related blogs introducing detailed implementation steps and principles

最后更新 4/17/2022 5:51 PM
dino.c
预计阅读 11 分钟
分类
WPF
专题
WPF UI Design
标签
.NET WPF WPF UI Design animation design

Wpf Design And Animation Lab

This is a WPF project to create and collect some fun designs and animations. There are currently dozens of demos, and some demos have related blogs introducing detailed implementation steps and principles:

设计和动画 - dino.c - 博客园

Through these blogs, you will learn how to implement some cool WPF animations and designs, as well as some WPF technical details.

1. Implemented design and animation

1.1 Use three methods to achieve an arc progress bar

image

There are many solutions to implement arc-shaped progress bars. By using Path and the three solutions of ArcSegment, Arc, and Ellipse, you can understand the basic usage of various shapes.

1.2 Implement cylindrical progress bars with only Rectangle

image

Cylindrical progress bars are not difficult to implement, but what's interesting is that the above figure consists entirely of a Rectangle representing a rectangle, which is slightly counterintuitive.

首先我们需要重温一些基础知识:Rectangle 显示带圆角的矩形。用 RadiusXRadiusY 可分别指定用于使矩形的角变圆的椭圆的 X 轴和 Y 轴半径。

As in the following example, you can see that the rounded corners of the Rectangle with RadiusX ="50" RadiusY ="20" and the Ellipse with Width ="100" Height ="40"(X-axis radius 50, Y-axis radius 20) completely coincide.

<Rectangle  Height="100"
            Width="100"
            Fill="#FF7E9EC0"
            Stroke="#FFFF0EC4"
            StrokeThickness="5"
            RadiusX="50"
            RadiusY="20" />
<Ellipse HorizontalAlignment="Left"
         VerticalAlignment="Top"
         StrokeThickness="5"
         Stroke="Yellow"
         Fill="Red"
         Width="100"
         Height="40"
         Opacity="0.5" />

image

Now we lengthen the rectangle above to form the basic shape of a cylinder; conversely, we flatten it to form the cross-section of a cylinder. Then set them to be translucent, which becomes the background of the cylindrical progress bar:

image

<Grid.Resources>
   <Style TargetType="Rectangle">
       <Setter Property="Fill" Value="#36a8e2" />
       <Setter Property="RadiusX" Value="25" />
       <Setter Property="RadiusY" Value="5" />
   </Style>
</Grid.Resources>
<Rectangle Opacity="0.2" />
<Rectangle Height="10"
          VerticalAlignment="Top"
          Opacity="0.1" />

Then add a layer of translucent gradient and another section to complete the cylindrical progress bar.

1.3 Play with rainbow text and animation

用 ItemsControl 拆分文字实现彩虹文字是一个很好玩的方案,因为可以对每个文字做不同的变形和动画,实现很多种玩法。首先,因为 string 是个集合,其实它可以用作 ItemsControl 的 ItemsSource。但在 Xaml 上直接写 ItemsSource="somestring"` 会报错,可以用 ContentControl 包装一下,写成这样:

<ContentControl Content="ItemsControl" >
    <ContentControl.Template>
        <ControlTemplate TargetType="ContentControl">
            <ItemsControl ItemsSource="{TemplateBinding Content}" >
            </ItemsControl>
        </ControlTemplate>
    </ContentControl.Template>
</ContentControl>

Then set the ItemsPanel of ItemsControl to arrange the content horizontally; set the DataTemplate to display the split characters on the TextBlock:

<ItemsControl ItemsSource="{TemplateBinding Content}" >
    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <StackPanel Orientation="Horizontal" />
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <TextBlock Text="{Binding}" />
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>

Next, in order for each character to display a different color, you need to implement a Collection class and instantiate it on Xaml, putting the colors used in it:

<common:RepeatCollection x:Key="RepeatCollection">
    <SolidColorBrush>#4a0e68</SolidColorBrush>
    <SolidColorBrush>#b62223</SolidColorBrush>
    <SolidColorBrush>#fdd70c</SolidColorBrush>
    <SolidColorBrush>#f16704</SolidColorBrush>
    <SolidColorBrush>#69982d</SolidColorBrush>
    <SolidColorBrush>#0075a5</SolidColorBrush>
    <SolidColorBrush>#0b0045</SolidColorBrush>
</common:RepeatCollection>

The code for this RepeatCollection is as follows. It is actually a circular queue, and each time the Next getter method is called, one element is taken down (would it be better to call CircleCollection?):

public class RepeatCollection : Collection<object>
{
    private int _offset;

    public object Next
    {
        get
        {
            if (this.Count == 0)
                return null;

            var result = this[_offset];
            _offset++;
            if (_offset > this.Count - 1)
                _offset = 0;

            return result;
        }
    }
}

Finally, the Foreground of TextBlock is bound to the Next property of the collection, realizing that each TextBlock uses a different color:

<TextBlock Foreground="{Binding Next, Source={StaticResource RepeatCollection}}" Text="{Binding}" />

image

Modify the above code to realize the animation of rainbow text:

image

1.4 Make a rainbow button

Apply Linear Gradient Brush to text, and the text turns rainbow color. If the Color between two Gradient Stop is the same, no gradient will occur, and if the Offset between two Gradient Stop will change immediately. Using this method, coupled with the use of constant width fonts, I can create rainbow text with different colors for each character:

<LinearGradientBrush x:Name="RainbowBrush" StartPoint="0,0.5" EndPoint="1,.5">
    <GradientStop x:Name="G1" Offset="0" Color="#65b849" />
    <GradientStop x:Name="G2" Offset=".166" Color="#65b849" />
    <GradientStop x:Name="G3" Offset=".166" Color="#f7b423" />
    <GradientStop x:Name="G4" Offset=".3333" Color="#f7b423" />
    <GradientStop x:Name="G5" Offset="0.3333" Color="#f58122" />
    <GradientStop x:Name="G6" Offset="0.5" Color="#f58122" />
    <GradientStop x:Name="G7" Offset="0.5" Color=" #f8f8f8" />
    <GradientStop x:Name="G8" Offset="0.5" Color=" #f8f8f8" />
    <GradientStop x:Name="G9" Offset="0.50" Color="#de3a3c" />
    <GradientStop x:Name="G10" Offset="0.666" Color="#de3a3c" />
    <GradientStop x:Name="G11" Offset="0.666" Color="#943f96" />
    <GradientStop x:Name="G12" Offset="0.8633" Color="#943f96" />
    <GradientStop x:Name="G13" Offset="0.8633" Color="#009fd9" />
    <GradientStop x:Name="G14" Offset="01" Color="#009fd9" />
</LinearGradientBrush>

image

Control Linear Gradient Brush to change direction in MouseOver's Storyboard. There are two ways to change its direction, one is to use PointAnimation to change StartPoint and EndPoint, and the other is to use DoubleAnimation to directly change Linear Gradient Brush. RelativeTransform. The latter is written as follows:

<Storyboard>
    <DoubleAnimation Storyboard.TargetName="textBlock"
                     Storyboard.TargetProperty="(TextBlock.Foreground).(Brush.RelativeTransform).(RotateTransform.Angle)"
                     To="90"
                     Duration="0:0:0.5">
        <DoubleAnimation.EasingFunction>
            <QuarticEase EasingMode="EaseOut" />
        </DoubleAnimation.EasingFunction>
    </DoubleAnimation>
</Storyboard>


<LinearGradientBrush x:Name="RainbowBrush" StartPoint="0,0.5" EndPoint="1,.5">
    <LinearGradientBrush.RelativeTransform>
        <RotateTransform Angle="0" CenterX="0.5" CenterY="0.5" />
    </LinearGradientBrush.RelativeTransform>

The effect when it works is to rotate all colors 90 degrees to look like the previous Apple Logo color scheme. In the Linear Gradient Brush above, I secretly hid two white Gradient Stop (named G6 and G7), and their Offset is 0.5, which is in the middle. In the Pressed state of the buttons, use DoubleAnimation to set the Offset of all GradientStop before and after them to 0 or 1. The effect is to push all colors to both sides. Because it is now rotated 90 degrees, it is actually pushing in two directions:

image

1.5 Implement loading animations for two Nintendo Switches

image

image

Using split text and TimeSpanIncreaser solutions, two of the most common animations on Nintendo Switch are implemented.

1.6 Write a Lighten Effect using Shazzam Shader Editor

In the above animation, a LightenConverter class is used in order to realize Grid with different brightness, but it can only process SolidColorBrush. In order to be applicable to more occasions, next, write an effect yourself to achieve the same Lighten effect.

image

1.7 Implementing WPF's Inner Shadow

In WPF, we usually use DropShadow for shadow effects, but we always use outer shadows. Inner Shadow is actually not impossible, it just has some twists and turns. There are several solutions to implement inner shadows, among which I like the best solution to use another element's VisualBrush to make OpacityMask.

<Grid Width="100"
      Height="100"
      Margin="10">
    <Rectangle x:Name="Rectangle2"
               Fill="White"
               RadiusX="8"
               RadiusY="8" />
    <Border Margin="0">
        <Border.Effect>
            <DropShadowEffect BlurRadius="8" ShadowDepth="0" />
        </Border.Effect>
        <ContentControl HorizontalAlignment="Center"
                        VerticalAlignment="Center"
                        Content="OpacityMask" />
    </Border>
    <Grid.OpacityMask>
        <VisualBrush Stretch="None" Visual="{Binding ElementName=Rectangle2}" />
    </Grid.OpacityMask>
</Grid>

But the shadow produced in this way will not be too thick. If you need a larger and thicker inner shadow, you can use a negative Margin and BorderThickness of the same thickness. Taking OpacityMask's solution as an example, you can make a thick and large inner shadow with the following code:

private void Slider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
{
    ShadowElement.Margin = new Thickness(-e.NewValue);
    ShadowElement.BorderThickness = new Thickness(e.NewValue);
    (ShadowElement.Effect as DropShadowEffect).BlurRadius = e.NewValue * 2;
}

image

1.8 Use OpacityMask to imitate UWP's Text Shimmer animation

image

There is a Text Shimmer animation in UWP's Windows Composition Samples that shows how to use Composition Light. This animation is simple. Use PointLight to scan a line of text from left to right. Although WPF does not have Composition Light, it is still okay to play this simple animation, just use OpacityMask to imitate it.

RadialGradientBrush 代表一个圆形的渐变画刷,在这里我们要关心它的三个属性:

    • RadiusX/RadiusY: ** Horizontal/vertical radius of the circle.
    • Center: ** The outermost center of the circle.
    • Gradient Origin: ** The position of the two-point focus at which the gradient begins.

The role of these three attributes can be referred to the following figure:

image

Use a RadialGradient Brush as OpacityMask to make TextBlock gradually transparent from the center point outwards:

<TextBlock HorizontalAlignment="Center"
           VerticalAlignment="Center"
           FontFamily="SegoeUI"
           FontSize="100"
           FontWeight="Thin"
           Foreground="DimGray"
           Text="Text Shimmer">
    <TextBlock.OpacityMask>
        <RadialGradientBrush x:Name="Brush" Center=".5,.5" GradientOrigin=".5,.5" RadiusX=".43" RadiusY="2">
            <GradientStop Color="Black" />
            <GradientStop Offset=".5" Color="#6000" />
            <GradientStop Offset="1" Color="#2000" />
        </RadialGradientBrush>
    </TextBlock.OpacityMask>
</TextBlock>

Then do PointAnimation on Center and Gradient Origin to realize the horizontal movement of OpacityMask, and you can imitate the effect of PointLight sweeping:

<PointAnimation RepeatBehavior="Forever"
                Storyboard.TargetName="Brush"
                Storyboard.TargetProperty="Center"
                From="-2,.5"
                To="3,.5"
                Duration="0:0:3.3" />
<PointAnimation RepeatBehavior="Forever"
                Storyboard.TargetName="Brush"
                Storyboard.TargetProperty="GradientOrigin"
                From="-2,.5"
                To="3,.5"
                Duration="0:0:3.3" />

1.9 Copy a button implemented by CSS3

image

Copy a button implemented by CSS3 and get familiar with CSS3.

1.10 Use Effect to achieve line light and shadow effects

image

To achieve this effect, I use these knowledge and skills:

  • Segoe Fluent icon font
  • Create Path in Blend
  • Calculate the long distance of Path
  • Path's border animation
  • Design-time data support for Visual Studio
  • Custom Effect

2. License

The project is released under MIT License.

3. Version of UWP

In addition, I have another project for playing UWP animations:

https://github.com/DinoChan/uwp_design_and_animation_lab

image

Reprinted from GitHub

Author: dino.c

Warehouse address: https://www.example.com

Keep Exploring

延伸阅读

更多文章
同分类 / 同标签 9/13/2025

Migration from WPF to Avalonia series: Why I have to migrate WPF programs to Avalonia

In the past few years, our host computer software has been mainly developed using WPF and WinForm. These technologies are really easy to use on the Windows platform, and they have also accompanied us through the stage of small-scale trial production to today's large-scale delivery. However, with the development of business and changes in customer needs, the single Windows technology stack has gradually become a hurdle that we must overcome.

继续阅读
同分类 / 同标签 1/26/2025

WPF internationalizes with custom XML files

This article describes in detail the methods of using custom XML files to achieve internationalization in WPF programs, including installing the necessary NuGet package, dynamically obtaining language lists, dynamically switching languages, using translation strings in code and xaml interfaces, etc. It also provides source code links to help developers easily internationalize WPF applications.

继续阅读