To try it out for yourself, download the demo app.
These kinds of animations have a range of applications:
- Instant feedback, when button is pressed or action performed
- Loading animations
- Progress bars, where animation progress = percentage progress
- Red flashes for warnings/alerts
The project was born while working on my upcoming new WPF application. I wanted a loading animation for a background task, that didn't take up space, and didn't prevent the user continuing using the app. The window borders seem a good place for this. And when the animation is only there for a few seconds, it isn't too distracting.
Older web browsers used to have very thin progress bars while a page was being fetched and rendered, so this doesn't seem too far fetched. In fact many modern web browsers still do, except pages load so fast it tends to be less noticable ... see the Chrome for Android screenshot below.
In web browsers these loading bars are placed between the application toolbar and the webpage content. For a desktop application that corresponds to placing it directly below the title bar, but above the window content. However, having tried this it looks a little strange, as if the title bar, being outside the border, isn't part of the application. Then I realised it really needs to be on the window border, which includes going above the title bar. Getting this to work in WPF was a bit of a pain, as it usually expects you to create graphic below the title bar, not above it. But eventually I found a reliable method.
Now I'll proceed to give a little FAQ summary, and explain the inner-workings.
Follow the instructions on the GitHub Readme. You can clone the project, and build on it. Or setup the required dependencies and copy the code into your own project.
Your Window class should take the following structure where <c:BorderLoop>
is the component containing one example border animation effect. Different components are available for different effects, each with different properties such as BColor
to set the color of the border animation.
<Window ...>
<Grid>
<!-- Add animations you want to use here -->
<c:BorderLoop x:Name="BorderLoop" BColor="Yellow"></c:BorderLoop>
<!-- Place your windows contents within this grid -->
<Grid Margin="1">
...
</Grid>
</Grid>
</Window>
Then to start the animation use the .Start()
method, e.g. BorderLoop.Start();
.
Can I use it for border animations on other WPF controls?
Yes. Use the same structure as above in place of your component:
<Grid>
<c:BorderLoop x:Name="BorderLoop" BColor="Yellow"></c:BorderLoop>
<MyControl Margin="1"/>
</Grid>
How does it add colours above the TitleBar?
To colour the borders, the window border width is actually set to 0, and custom controls are used within the window to make the colours appear. That means on the top border, a control has to be rendered above the titlebar. So how does that work?
In WPF titlebars are difficult to customise. Default WPF titlebars cannot be changed, hence they need to be removed entirely with a custom title bar put in their place. That's not an easy thing to do; you often loose native functionality by reimplementing titlebars youself. See my previous attempts creating customiable titlebars in WPF, and HTML-based WPF titlebars in blazor dektop apps.
... but WinUI provides much better controls for this. Hence I recommend using the ModernWpf framework which takes native titlebars from WinUI and lets you use them in your WPF application - and place additional controls like fake window borders within them! This project uses ModernWpf for this purpose.
How do the animations work? Are there performance overheads?
It uses WPF's built-in animations and storyboards … so it's very efficient.
However, animations in WPF are usually pixel based. You assign a From
value and a To
value in terms of pixels. This doesn't work very well for window border animation which need to span the full width or half-width or third-width of the window, and smoothly animate between these points in a way that scales correctly on window resizes. Of course that's never a problem in web development as CSS allow percentage based widths and heights, but sadly not in WPF 😢
Instead the way to achieve this in WPF is using Grids with column/row widths/heights using stars. E.g. setting a column to have width "43*" and a second column of width "100*" creates a 43:100 ratio or width of 43%.
Animating grid column widths and row heights like is this not possible out-of-the-box, instead I found an existing custom AnimationTimeline implementation from MahApps. You can find the source here.
You assign the component a name:
<Grid.ColumnDefinition Width="*" x:Name="MyColumn"/>
If you look at the codebehind for each animation component, you'll see the animations created like this:
GridLengthAnimation anim = new GridLengthAnimation();
anim.From = new GridLength(fromValue, GridUnitType.Star);
anim.To = new GridLength(toValue, GridUnitType.Star);
anim.Duration = ... ;
Storyboard.SetTargetName(anim, "MyColumn");
Storyboard.SetTargetProperty(anim, new PropertyPath(ColumnDefinition.WidthProperty));
The top dash animation is more complex, it consists of 16 columns which alernate between empty and coloured-in. The idea being that you only need to animate the widths of the first and last columns. The animation comes in two stages, first expanding width of column 2 and shrinking column 16, followed by expanding column 1 and shrinking column 15. After which, the animation immediately resets.
The complete border dash animation applies this to all 4 edges of the window at the same time, to make it look like the dashes are flowing around the entire window border.
That’s it
If you find it useful please star the GitHub repository ⭐⭐⭐
Comments
Post a Comment