使用 WPF 创建预加载控件

Introduction

At the time when WPF applications do a very long process like getting response from a web server, download file from a distant server, search files, etc., this control can be used to make the wait time more interactive. This is an alternative method to create preloader by using WPF methods instead of using GIF animation images. GIF animation might require more bitmap processing.

This demo will explain how to use this control in your projects. The solution used for this demo is created using Visual Studio 2008 (WPF, C#, .NET 3.5).

Using the Code

This user control is created with four rectangle blocks animated sequentially with Width property with a defined speed.

The following XAML is to create the rectangle block: Block.xaml

Height and width property is set by the PreLoaderControl.xaml control automatically. Developer would not require to change the values of these properties.

Hide   Copy Code

<UserControl x:Class="PreLoader.CustomControls.Block"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Height="Auto" Width="Auto">
    <Grid x:Name="PreLoaderBlock">
        <Rectangle Width="Auto" Height="Auto" Fill="Red" Margin="0">
            <Rectangle.Style>
                <Style TargetType="{x:Type Rectangle}">
                    <Setter Property="RenderOptions.BitmapScalingMode" Value="NearestNeighbor" />
                    <Setter Property="RenderOptions.EdgeMode" Value="Aliased" />
                </Style>
            </Rectangle.Style>
        </Rectangle>
    </Grid>
</UserControl>

The Fill property can be changed to your desired color or bind with a style theme.

Hide   Copy Code

Fill="{DynamicResource PreLoaderColor}"

The resource PreLoaderColor can be defined in the App.xaml or in any style theme.

Hide   Copy Code

<ResourceDictionary>
    <SolidColorBrush x:Key="PreLoaderColor" Color="Red" />
</ResourceDictionary>

The following xaml is to define the animation: PreLoaderControl.xaml.

The UserControl.Resources holds the definition for the storyboard animation targeting the Width property for all the four rectangle blocks defined in the Grid as shown below.

The speed of the animation can be adjusted with the property SpeedRatio.

Completed event is created in each storyboard to notify when the animation is completed respectively.

Hide   Shrink    Copy Code

<UserControl x:Class="PreLoader.CustomControls.PreLoaderControl"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:PreLoader.CustomControls"
    Height="{Binding}" Width="{Binding}" Loaded="UserControl_Loaded">
    <UserControl.Resources>
        <Storyboard x:Key="ProgressAnimation1" SpeedRatio="12">
            <DoubleAnimation Storyboard.TargetName="block1"
            Storyboard.TargetProperty="Width" From="16" To="0"
                             Completed="ProgressAnimation1_Completed" Duration="0:0:2"/>
        </Storyboard>
        <Storyboard x:Key="ProgressAnimation2" SpeedRatio="12">
            <DoubleAnimation Storyboard.TargetName="block2"
            Storyboard.TargetProperty="Width" From="16" To="0"
                             Completed="ProgressAnimation2_Completed" Duration="0:0:2" />
        </Storyboard>
        <Storyboard x:Key="ProgressAnimation3" SpeedRatio="12">
            <DoubleAnimation Storyboard.TargetName="block3"
            Storyboard.TargetProperty="Width" From="16" To="0"
                             Completed="ProgressAnimation3_Completed" Duration="0:0:2" />
        </Storyboard>
        <Storyboard x:Key="ProgressAnimation4" SpeedRatio="12">
            <DoubleAnimation Storyboard.TargetName="block4"
            Storyboard.TargetProperty="Width" From="16" To="0"
                             Completed="ProgressAnimation4_Completed" Duration="0:0:2" />
        </Storyboard>
    </UserControl.Resources>
    <Grid Width="Auto" Height="Auto" >
        <Grid HorizontalAlignment="Left" x:Name="gridBlock1"
        VerticalAlignment="Top" Margin="0,0,0,0" >
            <local:Block x:Name="block1" RenderTransformOrigin="0.5,4.3689"
            HorizontalAlignment="Stretch" Height="Auto"
            Width="Auto" VerticalAlignment="Stretch">
                <local:Block.RenderTransform>
                    <TransformGroup>
                        <ScaleTransform/>
                        <SkewTransform/>
                        <TranslateTransform/>
                    </TransformGroup>
                </local:Block.RenderTransform>
            </local:Block>
        </Grid>
        <Grid HorizontalAlignment="Right" x:Name="gridBlock2"
        VerticalAlignment="Top" Margin="0.5,0,0,0" >
            <local:Block x:Name="block2" RenderTransformOrigin="0.5,4.3689"
            HorizontalAlignment="Stretch" Height="Auto"
            Width="Auto" VerticalAlignment="Stretch">
                <local:Block.RenderTransform>
                    <TransformGroup>
                        <ScaleTransform />
                        <SkewTransform/>
                        <TranslateTransform/>
                    </TransformGroup>
                </local:Block.RenderTransform>
            </local:Block>
        </Grid>
        <Grid HorizontalAlignment="Right" x:Name="gridBlock3"
        VerticalAlignment="Bottom" Margin="0.5,0.5,0,0" >
            <local:Block x:Name="block3" RenderTransformOrigin="0.5,4.3689"
            HorizontalAlignment="Stretch" Height="Auto"
            Width="Auto" VerticalAlignment="Stretch">
                <local:Block.RenderTransform>
                    <TransformGroup>
                        <ScaleTransform/>
                        <SkewTransform/>
                        <TranslateTransform/>
                    </TransformGroup>
                </local:Block.RenderTransform>
            </local:Block>
        </Grid>
        <Grid HorizontalAlignment="Left" x:Name="gridBlock4"
        VerticalAlignment="Bottom" Margin="0,0.5,0,0" >
            <local:Block x:Name="block4" RenderTransformOrigin="0.5,4.3689"
            HorizontalAlignment="Stretch" Height="Auto"
            Width="Auto" VerticalAlignment="Stretch">
                <local:Block.RenderTransform>
                    <TransformGroup>
                        <ScaleTransform />
                        <SkewTransform/>
                        <TranslateTransform/>
                    </TransformGroup>
                </local:Block.RenderTransform>
            </local:Block>
        </Grid>
    </Grid>
</UserControl>

When the user control is loaded in the parent window, the width and height for all blocks is set automatically.

Hide   Copy Code

<local:PreLoaderControl Height="32" Width="32" />

Below is the code behind which actually controls the animation.

Hide   Shrink    Copy Code

namespace PreLoader.CustomControls
{
    public partial class PreLoaderControl : UserControl
    {

        // Flag variables used as a toggle to animate the block in both directions

        private bool Animation1RuningForward = true;
        private bool Animation2RuningForward = true;
        private bool Animation3RuningForward = true;
        private bool Animation4RuningForward = true;
        private double blockWidth = 16;

        public PreLoaderControl()
        {
            InitializeComponent();
        }

        // Calculate the width and height property based on the size defined in the parent
        // window where the control is added and starts the animation #1.

        private void UserControl_Loaded(object sender, RoutedEventArgs e)
        {
            Double blockSplitWidth = this.Width / 100;
            if (blockSplitWidth > 0.50)
                blockSplitWidth = 0.50;
            blockWidth = (this.Width / 2) - (blockSplitWidth * 4);
            double blockHeight = (this.Height / 2) - (blockSplitWidth * 4);
            gridBlock1.Width = blockWidth;
            gridBlock2.Width = blockWidth;
            gridBlock3.Width = blockWidth;
            gridBlock4.Width = blockWidth;
            gridBlock1.Height = blockHeight;
            gridBlock2.Height = blockHeight;
            gridBlock3.Height = blockHeight;
            gridBlock4.Height = blockHeight;
            StartAnimation("ProgressAnimation1", Animation1RuningForward);
        }

        // When the animation #1 is completed the following event function
        // will start the animation #2
        // Animation1RunningForward is toggled to animate the width from and to 0

        private void ProgressAnimation1_Completed(object sender, EventArgs e)
        {
            Animation1RuningForward = !Animation1RuningForward;
            StartAnimation("ProgressAnimation2", Animation2RuningForward);
        }

        // When the animation #2 is completed the following event function
        // will start the animation #3
        // Animation2RunningForward is toggled to animate the width from and to 0

        private void ProgressAnimation2_Completed(object sender, EventArgs e)
        {
            Animation2RuningForward = !Animation2RuningForward;
            StartAnimation("ProgressAnimation3", Animation3RuningForward);
        }

        // When the animation #3 is completed the following event function
        // will start the animation #4
        // Animation3RunningForward is toggled to animate the width from and to 0

        private void ProgressAnimation3_Completed(object sender, EventArgs e)
        {
            Animation3RuningForward = !Animation3RuningForward;
            StartAnimation("ProgressAnimation4", Animation4RuningForward);
        }

        // When the animation #4 is completed the following event function
        // will start the animation #1
        // Animation4RunningForward is toggled to animate the width from and to 0

        private void ProgressAnimation4_Completed(object sender, EventArgs e)
        {
            Animation4RuningForward = !Animation4RuningForward;
            StartAnimation("ProgressAnimation1", Animation1RuningForward);
        }

        // Begins the storyboard animation specified in the storyboardResourceName variable
        // The RunForward flag will toggle the widthFrom, widthTo values from 0 to
        // the calculated block width and vice versa.

        private void StartAnimation(String storyboardResourceName, bool RunForward)
        {
            double widthFrom = blockWidth;
            double widthTo = 0;
            if (RunForward)
            {
                widthFrom = blockWidth;
                widthTo = 0;
            }
            else
            {
                widthFrom = 0;
                widthTo = blockWidth;
            }
            Storyboard storyboard = this.FindResource(storyboardResourceName) as Storyboard;
            DoubleAnimation doubleanimation = storyboard.Children[0] as DoubleAnimation;
            doubleanimation.From = widthFrom;
            doubleanimation.To = widthTo;
            storyboard.Begin();
        }
    }
}

Below is the sample WPF window loaded with the above defined preloader control.

Create a new window, include the CustomControls folder containing Block.xaml and PreLoader.xaml.

Add the PreLoaderControl with the local tag in the grid and specify the Height and Width property values.

Hide   Copy Code

<Window x:Class="PreLoader.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:PreLoader.CustomControls"
    Title="Pre-loader control demo" Height="300" Width="300">
    <Grid>
        <Label Content="Pre-loader Control Demo" Height="28"
        VerticalAlignment="Top" HorizontalContentAlignment="Center"
        FontSize="16"></Label>
        <local:PreLoaderControl Height="32" Width="32" />
    </Grid>
</Window>

You can also add the control programmatically during run-time like the code below:

Hide   Copy Code

using Your_Namespace.CustomControls;

Your_Namespace will be the namespace defined in your solution and the CustomControls is the folder name where the usercontrol files are present.

Below is the sample pop-up window which loads the PreLoaderControl programmatically in the gridloaderGrid.

Hide   Copy Code

<Window x:Class="Your_NameSpace.WindowPreloader"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Status" Height="140" Width="250"
    Background="Transparent" xmlns:my="clr-namespace:Your_Namespace"
    ResizeMode="NoResize" ShowInTaskbar="False" WindowStartupLocation="CenterScreen"
    WindowStyle="None" Topmost="True" BorderThickness="0" AllowsTransparency="True"
    Closing="Window_Closing" Loaded="Window_Loaded" Icon="images/icon16.png">
    <Grid>
        <GroupBox Header="Processing..." Name="groupBoxHeader">
            <Grid x:Name="loaderGrid">
                <Label Name="labelStatus"
                Content="Please wait..." VerticalContentAlignment="Center"
                HorizontalAlignment="Right" Width="106" />
            </Grid>
        </GroupBox>
    </Grid>
</Window>

The following code loads the PreLoader control in the Window_Loaded event dynamically. In this example, thePreLoader control is created with the size of 64 includes all required parameters (like alignment, margin, etc.) set and added as children to the grid loaderGrid.

Hide   Copy Code

public partial class WindowPreloader : Window
{
    PreLoader preloader = null;

    public WindowPreloader()
    {
        InitializeComponent();
    }

    private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
    {
        preloader = null;
        //...
        // include other finalizing statements if you require
        //...
    }

    private void Window_Loaded(object sender, RoutedEventArgs e)
    {
        preloader = CommonFunctions.GetPreloader(64);
        preloader.HorizontalAlignment = HorizontalAlignment.Left;
        preloader.VerticalAlignment = VerticalAlignment.Center;
        preloader.Margin = new Thickness(20, 0, 0, 0);
        loaderGrid.Children.Add(preloader);
    }
} 

The following function will return the PreLoader control with the defined width and height specified in thesize parameter.

Hide   Copy Code

public PreLoader GetPreloader(int size)
{
    PreLoader preloader = new PreLoader();
    try
    {
        preloader.VerticalAlignment = VerticalAlignment.Center;
        preloader.HorizontalAlignment = HorizontalAlignment.Center;
        preloader.Width = size;
        preloader.Height = size;
        preloader.ToolTip = "Processing...";
    }
    catch (Exception ex)
    {
        //throw ex;
    }
    return (preloader);
}

As Control Library

You can also use this control by adding reference as the control library. Both the source and compiled DLL is available for download.

Create a new WPF project and include the existing (control library) project. Now add the reference ofDMACControls to your project.

In the below screenshot, the project is created as PreLoaderLibSample and the DMACControls is included in the reference.

In Window1 design, include the reference to the DMACControls as shown below:

Hide   Copy Code

xmlns:local="clr-namespace:DMACControls;assembly=DMACControls"

Now add the PreLoaderControl to your grid in Window1 with local tag and set the desired values forWidth and Height properties:

Hide   Copy Code

<Window x:Class="PreloaderLibSample.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:DMACControls;assembly=DMACControls"
    Title="Window1" Height="300" Width="300">
    <Grid>
        <Label Content="Pre-loader Control Demo" Height="28"
        VerticalAlignment="Top" HorizontalContentAlignment="Center"
        FontSize="16"></Label>
        <local:PreLoaderControl Height="32" Width="32" />
    </Grid>
</Window>

Ensure you set a static color or a dynamic resource style of the Block.xaml in the DMACControls project.

Changing the Color

Initially in this tip, the Rectangle is filled with static color Red as shown below:

Hide   Copy Code

<Rectangle Width="Auto" Height="Auto" Fill="Red" Margin="0">

Using the control library, the Fill property can be dynamically set with value set in app resources or in theme styles. From the below example, the Fill value for the Rectangle is set in App.xaml

Hide   Copy Code

<Rectangle Width="Auto" Height="Auto"
Fill="{DynamicResource PreLoaderColor}" Margin="0">

This can be found in Block.xaml in the DMACControls project:

Hide   Copy Code

<UserControl x:Class="DMACControls.Block"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Height="Auto" Width="Auto">
    <Grid x:Name="PreLoaderBlock">
        <Rectangle Width="Auto" Height="Auto"
        Fill="{DynamicResource PreLoaderColor}" Margin="0">
            <Rectangle.Style>
                <Style TargetType="{x:Type Rectangle}">
                    <Setter Property="RenderOptions.BitmapScalingMode" Value="NearestNeighbor" />
                    <Setter Property="RenderOptions.EdgeMode" Value="Aliased" />
                </Style>
            </Rectangle.Style>
        </Rectangle>
    </Grid>
</UserControl>

Open App.xaml in your WPF application project and set the color as shown below in key PreLoaderColor. AnyFill style like gradients, solid color, dynamic colors... can be set in the key PreLoaderColor.

Hide   Copy Code

<Application x:Class="PreloaderLibSample.App"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    StartupUri="Window1.xaml">
    <Application.Resources>
         <SolidColorBrush x:Key="PreLoaderColor" Color="Orange" />
    </Application.Resources>
</Application>

Ensure the key is defined in the App.xaml or in any theme files before you assign the DynamicResource in theFill property.

时间: 2024-10-07 00:48:39

使用 WPF 创建预加载控件的相关文章

下拉刷新上拉加载控件+Material Design使用

下拉刷新上拉加载控件+Material Design使用 人所缺乏的不是才干而是志向,不是成功的能力而是勤劳的意志. -- 部尔卫 Material Design控件使用 前几天分享了两篇Material Design控件使用的文章,这里就不多做叙述,下面是传送门,想要学习的小伙伴可以去看下: https://juejin.im/entry/58d8d4d344d90400687c134d/detail#comment https://juejin.im/entry/58d9cdf044d904

解决tableView中cell动态加载控件的重用问题

tableView的cell,有时候需要在运行时取得对应的数据后才能够动态的创建该cell中的控件并加载到该cell中,此时,你一定会遇到重用问题,即使你能做到该cell只根据数值加载了一回控件,你也没法保证不出现重用问题:) 效果(请注意查看,移动下面的格子时,上面出现了重用的问题) 源码: YXCell.h // // YXCell.h // YXTableView // // Copyright (c) 2014年 Y.X. All rights reserved. // #import

自个儿写Android的下拉刷新/上拉加载控件 (续)

本文算是对之前的一篇博文<自个儿写Android的下拉刷新/上拉加载控件>的续章,如果有兴趣了解更多的朋友可以先看一看之前的这篇博客. 事实上之所以会有之前的那篇博文的出现,是起因于前段时间自己在写一个练手的App时很快就遇到这种需求.其实我们可以发现类似这样下拉刷新.上拉加载的功能正在变得越来越普遍,可以说如今基本上绝大多数的应用里面都会使用到.当然,随着Android的发展,已经有不少现成的可以实现这种需求的"轮子"供我们使用了. 但转过头想一下想,既然本来就是自己练手

通用版的上拉刷新下拉加载控件

通用版的上拉刷新下拉加载控件 适用于各种控件实现上拉刷新,下拉加载的功能. 下载地址:http://www.devstore.cn/code/info/964.html 运行截图:    

自个儿写Android的下拉刷新/上拉加载控件

前段时间自己写了一个能够"通用"的,支持下拉刷新和上拉加载的自定义控件.可能现如今这已经不新鲜了,但有兴趣的朋友还是可以一起来看看的. 与通常的View配合使用(比如ImageView) 与ListView配合使用 与RecyclerView配合使用 与SrcollView配合使用 局部刷新(但想必这种需要实际应该还是不多的-.) 好啦,效果大概就是这样.如果您看后觉得有一点兴趣.那么,以下是相关的信息: GitHub地址: https://github.com/RawnHwang/S

[iOS微博项目 - 1.8] - 各种尺寸图片加载 &amp; 控件不显示研究

A. 图片的加载: [UIImage imageNamed:@"home"];  加载png图片    一.非retina屏幕  1.3.5 inch(320 x 480)  * home.png    二.retina屏幕  1.3.5 inch(640 x 960)  * [email protected]    2.4.0 inch(640 x 1136)  * [email protected](如果home是程序的启动图片,才支持自动加载)    三.举例(以下情况都是系统自

翻翻git之---基于universalimageloader实现的图片加载控件BlurImageView

转载请注明出处:王亟亟的大牛之路 昨天做了个梦,梦醒后觉得还是要更努力的学习,所以不多说废话,直接上货. BlurImageView 效果图: 流程: 实现原理,加载2张图片一张为很小的缩略图,一张为原图,缩略图加载完后做放大模糊处理,然后展开进度条加载原图,原图加载成功后替换缩略图. How to use? Grade: dependencies { compile 'com.wingjay:blurimageviewlib:1.1.0' } Eclipse: lib目录下面的3各类Copy进

上拉刷新下拉加载控件-PullToRefresh

在很多软件中,我们会用到上拉刷新,同时大多也会有下拉加载的功能,PullToRefresh这个控件就可以帮我们实现这个效果. 要使用这个空间首先我们要导包 布局文件 布局文件中就是添加了一个最简单的PullToRefreshListView <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/r

air mobile andriod ios 页面加载控件

通过最近的研究flex 书写android .ios申请书,我们遇到了一个问题加载页面,我们用flex sdk 12,air 15 无级似android ListView寻呼模块.所以,我和我的同事们写了一,效果依然能够,拖动刷新,向下拖动负载.走,假设你有更好的通知我一声,代码就直接帖出来吧. <?xml version="1.0" encoding="utf-8"?> <s:Application xmlns:fx="http://n