• WPFLoading遮层罩


    一直想实现这么个功能来着,所以去网上搜了资料,复杂的看不懂,后来挑了一个最简单的,复用了这位大神的很多代码(大神看到了别打脸大笑)。这位大神是用UserControl,使用时则是调用用户控件中的方法。之前有用过Telerik的RadBusyIndicator,感觉很好,它是将要遮罩部分直接以内容的形式包裹在RadBusyIndicator的Content属性中,使用时就更简单了,IsBusy=true时遮层罩开启,IsBusy=false遮层罩关闭/隐藏。一为了实现起来不复杂,二为了实现RadBusyIndicator的用法,实现自己的自定义控件,所以才有了这篇文章,先上效果图

    接下来先上自定义控件前台代码:

    <ResourceDictionary
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:MyBusyIndicator">
        
        <SolidColorBrush Color="#FF007BE5" x:Key="CirclesColor" />
        <Style TargetType="{x:Type local:BusyIndicator}">
            <Setter Property="Background" Value="#FFFFC0CB"/>
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type local:BusyIndicator}">
                        <Grid>
                            <ContentControl x:Name="PART_Content" Content="{TemplateBinding Content}" />
                            <Border x:Name="PART_Border" Visibility="Hidden" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}"
                                    Opacity="0.5">
                                
                            </Border>
                            <Grid x:Name="PART_LayoutRoot" 
                    Background="Transparent"    
                    ToolTip="Please wait...."    
                    HorizontalAlignment="Center"    
                    VerticalAlignment="Center" Visibility="Hidden">
     
                                <TextBlock Text="Loading..."  HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="14" Foreground="#FFE3953D" FontWeight="Bold" />
                                <Canvas RenderTransformOrigin="0.5,0.5" x:Name="PART_Canvas"
                        HorizontalAlignment="Center"    
                        VerticalAlignment="Center" Width="120"    
                        Height="120">
                                    <Ellipse x:Name="PART_C0" Width="20" Height="20"   
                             Canvas.Left="0"    
                             Canvas.Top="0" Stretch="Fill"    
                             Fill="{StaticResource CirclesColor}" Opacity="1.0"/>
                                    <Ellipse x:Name="PART_C1" Width="20" Height="20"   
                             Canvas.Left="0"    
                             Canvas.Top="0" Stretch="Fill"    
                             Fill="{StaticResource CirclesColor}" Opacity="0.9"/>
                                    <Ellipse x:Name="PART_C2" Width="20" Height="20"   
                             Canvas.Left="0"    
                             Canvas.Top="0" Stretch="Fill"    
                             Fill="{StaticResource CirclesColor}" Opacity="0.8"/>
                                    <Ellipse x:Name="PART_C3" Width="20" Height="20"   
                             Canvas.Left="0"    
                             Canvas.Top="0" Stretch="Fill"    
                             Fill="{StaticResource CirclesColor}" Opacity="0.7"/>
                                    <Ellipse x:Name="PART_C4" Width="20" Height="20"   
                             Canvas.Left="0"    
                             Canvas.Top="0" Stretch="Fill"    
                             Fill="{StaticResource CirclesColor}" Opacity="0.6"/>
                                    <Ellipse x:Name="PART_C5" Width="20" Height="20"   
                             Canvas.Left="0"    
                             Canvas.Top="0" Stretch="Fill"    
                             Fill="{StaticResource CirclesColor}" Opacity="0.5"/>
                                    <Ellipse x:Name="PART_C6" Width="20" Height="20"   
                             Canvas.Left="0"    
                             Canvas.Top="0" Stretch="Fill"    
                             Fill="{StaticResource CirclesColor}" Opacity="0.4"/>
                                    <Ellipse x:Name="PART_C7" Width="20" Height="20"   
                             Canvas.Left="0"    
                             Canvas.Top="0" Stretch="Fill"    
                             Fill="{StaticResource CirclesColor}" Opacity="0.3"/>
                                    <Ellipse x:Name="PART_C8" Width="20" Height="20"   
                             Canvas.Left="0"    
                             Canvas.Top="0" Stretch="Fill"    
                             Fill="{StaticResource CirclesColor}" Opacity="0.2"/>
                                    <Canvas.RenderTransform>
                                        <RotateTransform x:Name="PART_SpinnerRotate"   
                             Angle="0" />
                                    </Canvas.RenderTransform>
                                </Canvas>
                            </Grid>
                        </Grid>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </ResourceDictionary>

    下面的是自定义控件的后台逻辑和依赖属性:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Data;
    using System.Windows.Documents;
    using System.Windows.Input;
    using System.Windows.Media;
    using System.Windows.Media.Imaging;
    using System.Windows.Navigation;
    using System.Windows.Shapes;
    using System.Windows.Threading;
     
    namespace MyBusyIndicator
    {
        /// <summary>
        /// 按照步骤 1a 或 1b 操作,然后执行步骤 2 以在 XAML 文件中使用此自定义控件。
        ///
        /// 步骤 1a) 在当前项目中存在的 XAML 文件中使用该自定义控件。
        /// 将此 XmlNamespace 特性添加到要使用该特性的标记文件的根 
        /// 元素中: 
        ///
        ///     xmlns:MyNamespace="clr-namespace:MyBusyIndicator"
        ///
        ///
        /// 步骤 1b) 在其他项目中存在的 XAML 文件中使用该自定义控件。
        /// 将此 XmlNamespace 特性添加到要使用该特性的标记文件的根 
        /// 元素中: 
        ///
        ///     xmlns:MyNamespace="clr-namespace:MyBusyIndicator;assembly=MyBusyIndicator"
        ///
        /// 您还需要添加一个从 XAML 文件所在的项目到此项目的项目引用,
        /// 并重新生成以避免编译错误: 
        ///
        ///     在解决方案资源管理器中右击目标项目,然后依次单击
        ///     “添加引用”->“项目”->[浏览查找并选择此项目]
        ///
        ///
        /// 步骤 2)
        /// 继续操作并在 XAML 文件中使用控件。
        ///
        ///     <MyNamespace:BusyIndicator/>
        ///
        /// </summary>
        public class BusyIndicator : Control
        {
            private readonly DispatcherTimer animationTimer;
     
            public static readonly DependencyProperty IsBusyProperty;
     
            public static readonly DependencyProperty ContentProperty;
            static BusyIndicator()
            {
                DefaultStyleKeyProperty.OverrideMetadata(typeof(BusyIndicator), new FrameworkPropertyMetadata(typeof(BusyIndicator)));
     
                IsBusyProperty = DependencyProperty.Register("IsBusy", typeof(bool), typeof(BusyIndicator), new PropertyMetadata(false, new PropertyChangedCallback(OnBusyChanged)));
     
                ContentProperty = DependencyProperty.Register("Content", typeof(object), typeof(BusyIndicator));
            }
     
            public bool IsBusy
            {
                get { return (bool)GetValue(IsBusyProperty); }
                set { SetValue(IsBusyProperty, value); }
            }
     
            public object Content 
            {
                get { return GetValue(ContentProperty); }
                set { SetValue(ContentProperty, value); }
            }
     
            private static void OnBusyChanged(DependencyObject sender,DependencyPropertyChangedEventArgs e)
            {
                BusyIndicator indicator = sender as BusyIndicator;
                if ((bool)e.NewValue == true)
                {
                    indicator.Start();
                }
                else
                {
                    indicator.Stop();
                }
            }
     

            public BusyIndicator()
            {
                animationTimer = new DispatcherTimer(
                    DispatcherPriority.ContextIdle, Dispatcher);
                animationTimer.Interval = new TimeSpan(0, 0, 0, 0, 90);
            }
            #region Private Methods
            private void Start()
            {
                if (this.IsInitialized)
                {
                    Border border = GetTemplateChild("PART_Border") as Border;
                    border.Visibility = Visibility.Visible;
                    Grid grid = GetTemplateChild("PART_LayoutRoot") as Grid;
                    grid.Visibility = Visibility.Visible;
                    animationTimer.Tick += HandleAnimationTick;
                    animationTimer.Start();
                }
                
            }
     
            private void Stop()
            {
                if (this.IsInitialized)
                {
                    Border border = GetTemplateChild("PART_Border") as Border;
                    Grid grid = GetTemplateChild("PART_LayoutRoot") as Grid;
                    border.Visibility = Visibility.Hidden;
                    grid.Visibility = Visibility.Hidden;
                    animationTimer.Stop();
                    animationTimer.Tick -= HandleAnimationTick;
                }
            }
     
            private void HandleAnimationTick(object sender, EventArgs e)
            {
                RotateTransform SpinnerRotate = GetTemplateChild("PART_SpinnerRotate") as RotateTransform;
                SpinnerRotate.Angle = (SpinnerRotate.Angle + 36) % 360;
            }
     

            private void SetPosition(Ellipse ellipse, double offset,
                double posOffSet, double step)
            {
                ellipse.SetValue(Canvas.LeftProperty, 50.0
                    + Math.Sin(offset + posOffSet * step) * 50.0);
     
                ellipse.SetValue(Canvas.TopProperty, 50
                    + Math.Cos(offset + posOffSet * step) * 50.0);
            }
     
            public override void OnApplyTemplate()
            {
                base.OnApplyTemplate();
     
                const double offset = Math.PI;
                const double step = Math.PI * 2 / 10.0;
     
                Ellipse C0 = GetTemplateChild("PART_C0") as Ellipse;
                Ellipse C1 = GetTemplateChild("PART_C1") as Ellipse;
                Ellipse C2 = GetTemplateChild("PART_C2") as Ellipse;
                Ellipse C3 = GetTemplateChild("PART_C3") as Ellipse;
                Ellipse C4 = GetTemplateChild("PART_C4") as Ellipse;
                Ellipse C5 = GetTemplateChild("PART_C5") as Ellipse;
                Ellipse C6 = GetTemplateChild("PART_C6") as Ellipse;
                Ellipse C7 = GetTemplateChild("PART_C7") as Ellipse;
                Ellipse C8 = GetTemplateChild("PART_C8") as Ellipse;
     
                SetPosition(C0, offset, 0.0, step);
                SetPosition(C1, offset, 1.0, step);
                SetPosition(C2, offset, 2.0, step);
                SetPosition(C3, offset, 3.0, step);
                SetPosition(C4, offset, 4.0, step);
                SetPosition(C5, offset, 5.0, step);
                SetPosition(C6, offset, 6.0, step);
                SetPosition(C7, offset, 7.0, step);
                SetPosition(C8, offset, 8.0, step);
     
                if (this.IsBusy)
                {
                    this.Start();
                }
                else
                {
                    this.Stop();
                }
            }
     
            #endregion   
        }
    }

    以上便是全部控件的代码了,为了能够使用它,我将他单独编译成了一个dll,下面是如何使用该控件的例子,前台代码如下:

    <Window
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:local="clr-namespace:CustomControls"
            xmlns:telerik="http://schemas.telerik.com/2008/xaml/presentation"
            xmlns:System="clr-namespace:System;assembly=mscorlib" x:Class="CustomControls.MainWindow"
            xmlns:my="clr-namespace:MyBusyIndicator;assembly=MyBusyIndicator"
            Title="MainWindow" Height="350" Width="525" Loaded="Window_Loaded">
        <Grid>
            <my:BusyIndicator x:Name="busy">
                <my:BusyIndicator.Content>
                    <Grid>
                        <DataGrid>
                            <DataGrid.Columns>
                                <DataGridTextColumn Header="第一列"/>
                                <DataGridTextColumn Header="第二列"/>
                                <DataGridTextColumn Header="第三列"/>
                            </DataGrid.Columns>
                        </DataGrid>
                    </Grid>
                </my:BusyIndicator.Content>
            </my:BusyIndicator>
            <Button Content="Button" HorizontalAlignment="Right"  VerticalAlignment="Top" Width="75" Click="Button_Click"/>
        </Grid>
    </Window>

    记得注意引用的命名空间和程序集,下面是后台代码:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Data;
    using System.Windows.Documents;
    using System.Windows.Input;
    using System.Windows.Media;
    using System.Windows.Media.Imaging;
    using System.Windows.Navigation;
    using System.Windows.Shapes;
     
    namespace CustomControls
    {
        /// <summary>
        /// MainWindow.xaml 的交互逻辑
        /// </summary>
        public partial class MainWindow : Window
        {
            public MainWindow()
            {
                InitializeComponent();
            }
     
            private void Button_Click(object sender, RoutedEventArgs e)
            {
                busy.IsBusy = !busy.IsBusy;
            }
     
            private void Window_Loaded(object sender, RoutedEventArgs e)
            {
                busy.IsBusy = true;
            }
        }
    }

    OK,全部代码都已上。简单的说一句,不怎么会使用CSDN,不知道怎么插入代码,所以只好选择全部复制,一个很简单的控件。

  • 相关阅读:
    最近有人说我欺骗消费者,今天来一波视频分享
    前端 Java Python等资源合集大放送
    dubbo源码学习(四):暴露服务的过程
    dubbo源码学习(二) : spring 自定义标签
    Dubbo多注册中心和Zookeeper服务的迁移
    线程各种状态转换分析
    java并发之同步辅助类CountDownLatch
    工作5年的Java程序员,才学会阅读源码,可悲吗?
    【阿里面试系列】Java线程的应用及挑战
    「阿里面试系列」搞懂并发编程,轻松应对80%的面试场景
  • 原文地址:https://www.cnblogs.com/sjqq/p/8488935.html
Copyright © 2020-2023  润新知