WPF添加加载动画遮罩

项目中用到不少后台数据请求需要前端等待,添加加载动画改善用户体验

一、动画界面制作

添加一个自定义控件

<ResourceDictionary
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:CustomCtrlLib">
    
    
    <Storyboard x:Key="StoryLeftToRight" RepeatBehavior="Forever" Duration="00:00:01.50">
        <DoubleAnimationUsingKeyFrames
                BeginTime="00:00:00"
                Storyboard.TargetName="C0"
                Storyboard.TargetProperty="(FrameworkElement.Opacity)">
            <SplineDoubleKeyFrame KeyTime="00:00:00.00" Value="1.0" />
            <SplineDoubleKeyFrame KeyTime="00:00:00.15" Value="0.9" />
            <SplineDoubleKeyFrame KeyTime="00:00:00.30" Value="0.8" />
            <SplineDoubleKeyFrame KeyTime="00:00:00.45" Value="0.7" />
            <SplineDoubleKeyFrame KeyTime="00:00:00.60" Value="0.6" />
            <SplineDoubleKeyFrame KeyTime="00:00:00.75" Value="0.5" />
            <SplineDoubleKeyFrame KeyTime="00:00:00.90" Value="0.4" />
            <SplineDoubleKeyFrame KeyTime="00:00:01.05" Value="0.3" />
            <SplineDoubleKeyFrame KeyTime="00:00:01.20" Value="0.2" />
            <SplineDoubleKeyFrame KeyTime="00:00:01.35" Value="0.1" />
            <SplineDoubleKeyFrame KeyTime="00:00:01.50" Value="1.0" />
        </DoubleAnimationUsingKeyFrames>
        <DoubleAnimationUsingKeyFrames
                BeginTime="00:00:00"
                Storyboard.TargetName="C1"
                Storyboard.TargetProperty="(FrameworkElement.Opacity)">
            <SplineDoubleKeyFrame KeyTime="00:00:00.00" Value="0.9" />
            <SplineDoubleKeyFrame KeyTime="00:00:00.15" Value="0.8" />
            <SplineDoubleKeyFrame KeyTime="00:00:00.30" Value="0.7" />
            <SplineDoubleKeyFrame KeyTime="00:00:00.45" Value="0.6" />
            <SplineDoubleKeyFrame KeyTime="00:00:00.60" Value="0.5" />
            <SplineDoubleKeyFrame KeyTime="00:00:00.75" Value="0.4" />
            <SplineDoubleKeyFrame KeyTime="00:00:00.90" Value="0.3" />
            <SplineDoubleKeyFrame KeyTime="00:00:01.05" Value="0.2" />
            <SplineDoubleKeyFrame KeyTime="00:00:01.20" Value="0.1" />
            <SplineDoubleKeyFrame KeyTime="00:00:01.35" Value="1.0" />
            <SplineDoubleKeyFrame KeyTime="00:00:01.50" Value="0.9" />
        </DoubleAnimationUsingKeyFrames>
        <DoubleAnimationUsingKeyFrames
                BeginTime="00:00:00"
                Storyboard.TargetName="C2"
                Storyboard.TargetProperty="(FrameworkElement.Opacity)">
            <SplineDoubleKeyFrame KeyTime="00:00:00.00" Value="0.8" />
            <SplineDoubleKeyFrame KeyTime="00:00:00.15" Value="0.7" />
            <SplineDoubleKeyFrame KeyTime="00:00:00.30" Value="0.6" />
            <SplineDoubleKeyFrame KeyTime="00:00:00.45" Value="0.5" />
            <SplineDoubleKeyFrame KeyTime="00:00:00.60" Value="0.4" />
            <SplineDoubleKeyFrame KeyTime="00:00:00.75" Value="0.3" />
            <SplineDoubleKeyFrame KeyTime="00:00:00.90" Value="0.2" />
            <SplineDoubleKeyFrame KeyTime="00:00:01.05" Value="0.1" />
            <SplineDoubleKeyFrame KeyTime="00:00:01.20" Value="1.0" />
            <SplineDoubleKeyFrame KeyTime="00:00:01.35" Value="0.9" />
            <SplineDoubleKeyFrame KeyTime="00:00:01.50" Value="0.8" />
        </DoubleAnimationUsingKeyFrames>
        <DoubleAnimationUsingKeyFrames
                BeginTime="00:00:00"
                Storyboard.TargetName="C3"
                 Storyboard.TargetProperty="(FrameworkElement.Opacity)">
            <SplineDoubleKeyFrame KeyTime="00:00:00.00" Value="0.7" />
            <SplineDoubleKeyFrame KeyTime="00:00:00.15" Value="0.6" />
            <SplineDoubleKeyFrame KeyTime="00:00:00.30" Value="0.5" />
            <SplineDoubleKeyFrame KeyTime="00:00:00.45" Value="0.4" />
            <SplineDoubleKeyFrame KeyTime="00:00:00.60" Value="0.3" />
            <SplineDoubleKeyFrame KeyTime="00:00:00.75" Value="0.2" />
            <SplineDoubleKeyFrame KeyTime="00:00:00.90" Value="0.1" />
            <SplineDoubleKeyFrame KeyTime="00:00:01.05" Value="1.0" />
            <SplineDoubleKeyFrame KeyTime="00:00:01.20" Value="0.9" />
            <SplineDoubleKeyFrame KeyTime="00:00:01.35" Value="0.8" />
            <SplineDoubleKeyFrame KeyTime="00:00:01.50" Value="0.7" />
        </DoubleAnimationUsingKeyFrames>
        <DoubleAnimationUsingKeyFrames
                BeginTime="00:00:00"
                Storyboard.TargetName="C4"
                 Storyboard.TargetProperty="(FrameworkElement.Opacity)">
            <SplineDoubleKeyFrame KeyTime="00:00:00.00" Value="0.6" />
            <SplineDoubleKeyFrame KeyTime="00:00:00.15" Value="0.5" />
            <SplineDoubleKeyFrame KeyTime="00:00:00.30" Value="0.4" />
            <SplineDoubleKeyFrame KeyTime="00:00:00.45" Value="0.3" />
            <SplineDoubleKeyFrame KeyTime="00:00:00.60" Value="0.2" />
            <SplineDoubleKeyFrame KeyTime="00:00:00.75" Value="0.1" />
            <SplineDoubleKeyFrame KeyTime="00:00:00.90" Value="1.0" />
            <SplineDoubleKeyFrame KeyTime="00:00:01.05" Value="0.9" />
            <SplineDoubleKeyFrame KeyTime="00:00:01.20" Value="0.8" />
            <SplineDoubleKeyFrame KeyTime="00:00:01.35" Value="0.7" />
            <SplineDoubleKeyFrame KeyTime="00:00:01.50" Value="0.6" />
        </DoubleAnimationUsingKeyFrames>
        <DoubleAnimationUsingKeyFrames
                BeginTime="00:00:00"
                Storyboard.TargetName="C5"
                 Storyboard.TargetProperty="(FrameworkElement.Opacity)">
            <SplineDoubleKeyFrame KeyTime="00:00:00.00" Value="0.5" />
            <SplineDoubleKeyFrame KeyTime="00:00:00.15" Value="0.4" />
            <SplineDoubleKeyFrame KeyTime="00:00:00.30" Value="0.3" />
            <SplineDoubleKeyFrame KeyTime="00:00:00.45" Value="0.2" />
            <SplineDoubleKeyFrame KeyTime="00:00:00.60" Value="0.1" />
            <SplineDoubleKeyFrame KeyTime="00:00:00.75" Value="1.0" />
            <SplineDoubleKeyFrame KeyTime="00:00:00.90" Value="0.9" />
            <SplineDoubleKeyFrame KeyTime="00:00:01.05" Value="0.8" />
            <SplineDoubleKeyFrame KeyTime="00:00:01.20" Value="0.7" />
            <SplineDoubleKeyFrame KeyTime="00:00:01.35" Value="0.6" />
            <SplineDoubleKeyFrame KeyTime="00:00:01.50" Value="0.5" />
        </DoubleAnimationUsingKeyFrames>
        <DoubleAnimationUsingKeyFrames
                BeginTime="00:00:00"
                Storyboard.TargetName="C6"
                 Storyboard.TargetProperty="(FrameworkElement.Opacity)">
            <SplineDoubleKeyFrame KeyTime="00:00:00.00" Value="0.4" />
            <SplineDoubleKeyFrame KeyTime="00:00:00.15" Value="0.3" />
            <SplineDoubleKeyFrame KeyTime="00:00:00.30" Value="0.2" />
            <SplineDoubleKeyFrame KeyTime="00:00:00.45" Value="0.1" />
            <SplineDoubleKeyFrame KeyTime="00:00:00.60" Value="1.0" />
            <SplineDoubleKeyFrame KeyTime="00:00:00.75" Value="0.9" />
            <SplineDoubleKeyFrame KeyTime="00:00:00.90" Value="0.8" />
            <SplineDoubleKeyFrame KeyTime="00:00:01.05" Value="0.7" />
            <SplineDoubleKeyFrame KeyTime="00:00:01.20" Value="0.6" />
            <SplineDoubleKeyFrame KeyTime="00:00:01.35" Value="0.5" />
            <SplineDoubleKeyFrame KeyTime="00:00:01.50" Value="0.4" />
        </DoubleAnimationUsingKeyFrames>
        <DoubleAnimationUsingKeyFrames
                BeginTime="00:00:00"
                Storyboard.TargetName="C7"
                 Storyboard.TargetProperty="(FrameworkElement.Opacity)">
            <SplineDoubleKeyFrame KeyTime="00:00:00.00" Value="0.3" />
            <SplineDoubleKeyFrame KeyTime="00:00:00.15" Value="0.2" />
            <SplineDoubleKeyFrame KeyTime="00:00:00.30" Value="0.1" />
            <SplineDoubleKeyFrame KeyTime="00:00:00.45" Value="1.0" />
            <SplineDoubleKeyFrame KeyTime="00:00:00.60" Value="0.9" />
            <SplineDoubleKeyFrame KeyTime="00:00:00.75" Value="0.8" />
            <SplineDoubleKeyFrame KeyTime="00:00:00.90" Value="0.7" />
            <SplineDoubleKeyFrame KeyTime="00:00:01.05" Value="0.6" />
            <SplineDoubleKeyFrame KeyTime="00:00:01.20" Value="0.5" />
            <SplineDoubleKeyFrame KeyTime="00:00:01.35" Value="0.4" />
            <SplineDoubleKeyFrame KeyTime="00:00:01.50" Value="0.3" />
        </DoubleAnimationUsingKeyFrames>
        <DoubleAnimationUsingKeyFrames
                BeginTime="00:00:00"
                Storyboard.TargetName="C8"
                 Storyboard.TargetProperty="(FrameworkElement.Opacity)">
            <SplineDoubleKeyFrame KeyTime="00:00:00.00" Value="0.2" />
            <SplineDoubleKeyFrame KeyTime="00:00:00.15" Value="0.1" />
            <SplineDoubleKeyFrame KeyTime="00:00:00.30" Value="1.0" />
            <SplineDoubleKeyFrame KeyTime="00:00:00.45" Value="0.9" />
            <SplineDoubleKeyFrame KeyTime="00:00:00.60" Value="0.8" />
            <SplineDoubleKeyFrame KeyTime="00:00:00.75" Value="0.7" />
            <SplineDoubleKeyFrame KeyTime="00:00:00.90" Value="0.6" />
            <SplineDoubleKeyFrame KeyTime="00:00:01.05" Value="0.5" />
            <SplineDoubleKeyFrame KeyTime="00:00:01.20" Value="0.4" />
            <SplineDoubleKeyFrame KeyTime="00:00:01.35" Value="0.3" />
            <SplineDoubleKeyFrame KeyTime="00:00:01.50" Value="0.2" />
        </DoubleAnimationUsingKeyFrames>
        <DoubleAnimationUsingKeyFrames
                BeginTime="00:00:00"
                Storyboard.TargetName="C9"
                 Storyboard.TargetProperty="(FrameworkElement.Opacity)">
            <SplineDoubleKeyFrame KeyTime="00:00:00.00" Value="0.1" />
            <SplineDoubleKeyFrame KeyTime="00:00:00.15" Value="1.0" />
            <SplineDoubleKeyFrame KeyTime="00:00:00.30" Value="0.9" />
            <SplineDoubleKeyFrame KeyTime="00:00:00.45" Value="0.8" />
            <SplineDoubleKeyFrame KeyTime="00:00:00.60" Value="0.7" />
            <SplineDoubleKeyFrame KeyTime="00:00:00.75" Value="0.6" />
            <SplineDoubleKeyFrame KeyTime="00:00:00.90" Value="0.5" />
            <SplineDoubleKeyFrame KeyTime="00:00:01.05" Value="0.4" />
            <SplineDoubleKeyFrame KeyTime="00:00:01.20" Value="0.3" />
            <SplineDoubleKeyFrame KeyTime="00:00:01.35" Value="0.2" />
            <SplineDoubleKeyFrame KeyTime="00:00:01.50" Value="0.1" />
        </DoubleAnimationUsingKeyFrames>
    </Storyboard>

    

    <Style TargetType="{x:Type local:LoadingView}">
        <Setter Property="Template">
            <Setter.Value>
                <!--控件模板-->
                <ControlTemplate TargetType="{x:Type local:LoadingView}">
                    <StackPanel VerticalAlignment="Center">
                        <Canvas RenderTransformOrigin="0.5,0.5" HorizontalAlignment="Center"  VerticalAlignment="Center" Width="120"  Height="120">
                            <Canvas.Triggers>
                                <EventTrigger RoutedEvent="FrameworkElement.Loaded">
                                    <BeginStoryboard Storyboard="{StaticResource StoryLeftToRight}" />
                                </EventTrigger>
                            </Canvas.Triggers>
                            <Ellipse x:Name="C0" Width="20" Height="20" Canvas.Left="50" Canvas.Top="0" Stretch="Fill" Fill="#D8C5A5" Opacity="1.0"/>
                            <Ellipse x:Name="C1" Width="20" Height="20" Canvas.Left="20.61073738537635"  Canvas.Top="9.54915028125263" Stretch="Fill"  Fill="#D8C5A5" Opacity="0.9"/>
                            <Ellipse x:Name="C2" Width="20" Height="20" Canvas.Left="2.447174185242325"  Canvas.Top="34.549150281252622" Stretch="Fill" Fill="#D8C5A5" Opacity="0.8"/>
                            <Ellipse x:Name="C3" Width="20" Height="20" Canvas.Left="2.4471741852423179"  Canvas.Top="65.450849718747364" Stretch="Fill" Fill="#D8C5A5" Opacity="0.7"/>
                            <Ellipse x:Name="C4" Width="20" Height="20" Canvas.Left="20.610737385376332" Canvas.Top="90.450849718747364" Stretch="Fill" Fill="#D8C5A5" Opacity="0.6"/>
                            <Ellipse x:Name="C5" Width="20" Height="20" Canvas.Left="50" Canvas.Top="100" Stretch="Fill" Fill="#D8C5A5" Opacity="0.5"/>
                            <Ellipse x:Name="C6" Width="20" Height="20" Canvas.Left="79.389262614623647"  Canvas.Top="90.450849718747378" Stretch="Fill" Fill="#D8C5A5" Opacity="0.4"/>
                            <Ellipse x:Name="C7" Width="20" Height="20" Canvas.Left="97.552825814757682" Canvas.Top="65.450849718747392" Stretch="Fill" Fill="#D8C5A5" Opacity="0.3"/>
                            <Ellipse x:Name="C8" Width="20" Height="20" Canvas.Left="97.552825814757682" Canvas.Top="34.549150281252643" Stretch="Fill"  Fill="#D8C5A5" Opacity="0.2"/>
                            <Ellipse x:Name="C9" Width="20" Height="20"  Canvas.Left="79.389262614623675" Canvas.Top="9.5491502812526363" Stretch="Fill" Fill="#D8C5A5" Opacity="0.1"/>
                            <Canvas.RenderTransform>
                                <RotateTransform x:Name="SpinnerRotate"  Angle="0" />
                            </Canvas.RenderTransform>
                        </Canvas>
                        <TextBlock Text="{TemplateBinding Message}" HorizontalAlignment="Center" FontSize="30" Foreground="#D8C5A5" Margin="0,10,0,0"></TextBlock>
                    </StackPanel>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</ResourceDictionary>

对应类定义,添加了一个依赖属性,可让用户自定义加载时显示的文本

using System.Windows;
using System.Windows.Controls;

namespace CustomCtrlLib
{
    /// <summary>
    /// Follow steps 1a or 1b and then 2 to use this custom control in a XAML file.
    ///
    /// Step 1a) Using this custom control in a XAML file that exists in the current project.
    /// Add this XmlNamespace attribute to the root element of the markup file where it is 
    /// to be used:
    ///
    ///     xmlns:MyNamespace="clr-namespace:CustomCtrlLib"
    ///
    ///
    /// Step 1b) Using this custom control in a XAML file that exists in a different project.
    /// Add this XmlNamespace attribute to the root element of the markup file where it is 
    /// to be used:
    ///
    ///     xmlns:MyNamespace="clr-namespace:CustomCtrlLib;assembly=CustomCtrlLib"
    ///
    /// You will also need to add a project reference from the project where the XAML file lives
    /// to this project and Rebuild to avoid compilation errors:
    ///
    ///     Right click on the target project in the Solution Explorer and
    ///     "Add Reference"->"Projects"->[Select this project]
    ///
    ///
    /// Step 2)
    /// Go ahead and use your control in the XAML file.
    ///
    ///     <MyNamespace:CustomControl1/>
    ///
    /// </summary>
    public class LoadingView : Control
    {
        static LoadingView()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(LoadingView), new FrameworkPropertyMetadata(typeof(LoadingView)));
        }

        public static readonly DependencyProperty MessageProperty = DependencyProperty.Register("Message", typeof(string), typeof(LoadingView));
        /// <summary>
        /// 默认文本
        /// </summary>
        public string Message
        {
            get { return (string)GetValue(MessageProperty); }
            set { SetValue(MessageProperty, value); }
        }
    }
}

二、使用时可以在最外层加个遮罩,在后台设置Loading的值来控制动画是否显示

<!--Loading Mask-->
        <Border Grid.RowSpan="2" Visibility="{Binding Path=Loading, Mode=TwoWay}" HorizontalAlignment="Stretch" Background="#004B64" Opacity="0.3" IsEnabled="False"
                VerticalAlignment="Stretch">
            <CustomLib:LoadingView Message="Loading"></CustomLib:LoadingView>
        </Border>

三、prism中module间通信

项目中是一个主窗口里开tab页方式,如果是tab中界面加载时,动画是要遮住整个主窗口的,这样遮罩定义只能放在主窗口中,就需要在tab界面中将是否显示传递给主窗口。项目使用的是prism框架,在这使用Event Aggregation事件聚合实现。

添加一个事件供发布订阅,参数是bool类型

public class LoadingSentEvent : PubSubEvent<bool>
    {
    }

在主窗口订阅事件

 private Visibility _loading = Visibility.Collapsed;
        public Visibility Loading
        {
            get { return _loading; }
            set { SetProperty(ref _loading, value); }
        }

        IEventAggregator _eventAggregator;

        public MainWindowViewModel(IEventAggregator eventAggregator)
        {
            _eventAggregator = eventAggregator;
            _eventAggregator.GetEvent<LoadingSentEvent>().Subscribe(LoadingReceived);
        }

        private void LoadingReceived(bool flag)
        {
            if (flag)
                Loading = Visibility.Visible;
            else
                Loading = Visibility.Collapsed;
        }

在需要的页面发布事件

readonly IEventAggregator _eventAggregator;
_eventAggregator.GetEvent<LoadingSentEvent>().Publish(true);  //显示加载界面
_eventAggregator.GetEvent<LoadingSentEvent>().Publish(false);  //隐藏加载界面

WPF MVVM 中实现等待的功能可以通过以下步骤完成: 1. 创建一个布尔类型的属性,用于表示等待状态,例如 `IsWaiting`。 2. 在视图模型中,当需要进行等待操作时,将 `IsWaiting` 属性设置为 `true`。 3. 在视图中,可以使用一个遮罩层或者进度条等控件来展示等待的效果。可以使用一个绑定来将 `IsWaiting` 属性与控件的可见性或者动画效果进行绑定。 4. 等待完成后,将 `IsWaiting` 属性设置为 `false`,隐藏等待的控件。 下面是一个简单的示例代码: ```csharp // 在视图模型中定义 IsWaiting 属性 public class MainViewModel : INotifyPropertyChanged { private bool isWaiting; public bool IsWaiting { get { return isWaiting; } set { isWaiting = value; OnPropertyChanged(nameof(IsWaiting)); } } // 假设有一个需要进行等待的方法 public async Task WaitForSomethingAsync() { IsWaiting = true; // 执行等待操作 IsWaiting = false; } // INotifyPropertyChanged 接口实现代码... } ``` ```xaml <!-- 在视图中使用遮罩层来展示等待的效果 --> <Grid> <!-- 其他界面内容... --> <!-- 遮罩层 --> <Border Background="Gray" Opacity="0.5" Visibility="{Binding IsWaiting, Converter={StaticResource BoolToVisibilityConverter}}"> <TextBlock Text="Waiting..." HorizontalAlignment="Center" VerticalAlignment="Center"/> </Border> </Grid> ``` 在上述代码中,`MainViewModel` 类中的 `IsWaiting` 属性用于表示等待状态,当需要进行等待操作时,将其设置为 `true`,等待完成后设置为 `false`。在视图中,使用一个 `Border` 控件作为遮罩层来展示等待的效果,通过绑定 `IsWaiting` 属性与 `Visibility` 属性来控制遮罩层的显示与隐藏。 这样,在进行等待操作时,设置 `IsWaiting` 为 `true`,遮罩层将显示出来,表明正在等待;等待完成后,设置 `IsWaiting` 为 `false`,遮罩层将隐藏起来,等待效果结束。 请注意,上述代码只是一个简单示例,实际应用中可能会有更复杂的等待操作和界面布局,你可以根据具体需求进行适配和扩展。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值