博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
WPF自定义控件与样式(11)-等待/忙/正在加载状态-控件实现
阅读量:5922 次
发布时间:2019-06-19

本文共 19032 字,大约阅读时间需要 63 分钟。

一.前言

  申明:WPF自定义控件与样式是一个系列文章,前后是有些关联的,但大多是按照由简到繁的顺序逐步发布的等,若有不明白的地方可以参考本系列前面的文章,文末附有部分文章链接。

  本文主要有三种实现方式

  • 简单忙碌状态控件BusyBox;
  • Win8/win10效果忙碌状态控件ProgressRing;
  • 弹出异步等待框WaitingBox;

二.简单忙碌状态控件BusyBox

  效果图:

 

  通过属性"IsActive"控制控件是否启用,后台C#代码:  

///     /// BusyBox.xaml 的交互逻辑    ///     public partial class BusyBox : UserControl    {        public static readonly DependencyProperty IsActiveProperty = DependencyProperty.Register("IsActive", typeof(bool), typeof(BusyBox), new PropertyMetadata(false));        ///         /// 是否启用        ///         public bool IsActive        {            get { return (bool)GetValue(IsActiveProperty); }            set { SetValue(IsActiveProperty, value); }        }        static BusyBox()        {            DefaultStyleKeyProperty.OverrideMetadata(typeof(BusyBox), new FrameworkPropertyMetadata(typeof(BusyBox)));        }    }

  使用了一个字体图标,触发器中实现动画显示的控制,样式代码:  

  使用示例:  

IsActive

 

三.Win8/win10效果忙碌状态控件ProgressRing

  这是网上一个开源项目里的控件,项目地址:。不做多介绍了,效果图:

 

  后台C#代码:  

[TemplateVisualState(Name = "Large", GroupName = "SizeStates")]    [TemplateVisualState(Name = "Small", GroupName = "SizeStates")]    [TemplateVisualState(Name = "Inactive", GroupName = "ActiveStates")]    [TemplateVisualState(Name = "Active", GroupName = "ActiveStates")]    public class ProgressRing : Control    {        public static readonly DependencyProperty BindableWidthProperty = DependencyProperty.Register("BindableWidth", typeof(double), typeof(ProgressRing), new PropertyMetadata(default(double), BindableWidthCallback));        public static readonly DependencyProperty IsActiveProperty = DependencyProperty.Register("IsActive", typeof(bool), typeof(ProgressRing), new FrameworkPropertyMetadata(default(bool), FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, IsActiveChanged));        public static readonly DependencyProperty IsLargeProperty = DependencyProperty.Register("IsLarge", typeof(bool), typeof(ProgressRing), new PropertyMetadata(true, IsLargeChangedCallback));        public static readonly DependencyProperty MaxSideLengthProperty = DependencyProperty.Register("MaxSideLength", typeof(double), typeof(ProgressRing), new PropertyMetadata(default(double)));        public static readonly DependencyProperty EllipseDiameterProperty = DependencyProperty.Register("EllipseDiameter", typeof(double), typeof(ProgressRing), new PropertyMetadata(default(double)));        public static readonly DependencyProperty EllipseOffsetProperty = DependencyProperty.Register("EllipseOffset", typeof(Thickness), typeof(ProgressRing), new PropertyMetadata(default(Thickness)));        private List
_deferredActions = new List
(); static ProgressRing() { DefaultStyleKeyProperty.OverrideMetadata(typeof(ProgressRing), new FrameworkPropertyMetadata(typeof(ProgressRing))); VisibilityProperty.OverrideMetadata(typeof(ProgressRing), new FrameworkPropertyMetadata( new PropertyChangedCallback( (ringObject, e) => { if (e.NewValue != e.OldValue) { var ring = (ProgressRing)ringObject; //auto set IsActive to false if we're hiding it. if ((Visibility)e.NewValue != Visibility.Visible) { //sets the value without overriding it's binding (if any). ring.SetCurrentValue(ProgressRing.IsActiveProperty, false); } else { // #1105 don't forget to re-activate ring.IsActive = true; } } }))); } public ProgressRing() { SizeChanged += OnSizeChanged; } public double MaxSideLength { get { return (double)GetValue(MaxSideLengthProperty); } private set { SetValue(MaxSideLengthProperty, value); } } public double EllipseDiameter { get { return (double)GetValue(EllipseDiameterProperty); } private set { SetValue(EllipseDiameterProperty, value); } } public Thickness EllipseOffset { get { return (Thickness)GetValue(EllipseOffsetProperty); } private set { SetValue(EllipseOffsetProperty, value); } } public double BindableWidth { get { return (double)GetValue(BindableWidthProperty); } private set { SetValue(BindableWidthProperty, value); } } public bool IsActive { get { return (bool)GetValue(IsActiveProperty); } set { SetValue(IsActiveProperty, value); } } public bool IsLarge { get { return (bool)GetValue(IsLargeProperty); } set { SetValue(IsLargeProperty, value); } } private static void BindableWidthCallback(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs) { var ring = dependencyObject as ProgressRing; if (ring == null) return; var action = new Action(() => { ring.SetEllipseDiameter( (double)dependencyPropertyChangedEventArgs.NewValue); ring.SetEllipseOffset( (double)dependencyPropertyChangedEventArgs.NewValue); ring.SetMaxSideLength( (double)dependencyPropertyChangedEventArgs.NewValue); }); if (ring._deferredActions != null) ring._deferredActions.Add(action); else action(); } private void SetMaxSideLength(double width) { MaxSideLength = width <= 20 ? 20 : width; } private void SetEllipseDiameter(double width) { EllipseDiameter = width / 8; } private void SetEllipseOffset(double width) { EllipseOffset = new Thickness(0, width / 2, 0, 0); } private static void IsLargeChangedCallback(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs) { var ring = dependencyObject as ProgressRing; if (ring == null) return; ring.UpdateLargeState(); } private void UpdateLargeState() { Action action; if (IsLarge) action = () => VisualStateManager.GoToState(this, "Large", true); else action = () => VisualStateManager.GoToState(this, "Small", true); if (_deferredActions != null) _deferredActions.Add(action); else action(); } private void OnSizeChanged(object sender, SizeChangedEventArgs sizeChangedEventArgs) { BindableWidth = ActualWidth; } private static void IsActiveChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs) { var ring = dependencyObject as ProgressRing; if (ring == null) return; ring.UpdateActiveState(); } private void UpdateActiveState() { Action action; if (IsActive) action = () => VisualStateManager.GoToState(this, "Active", true); else action = () => VisualStateManager.GoToState(this, "Inactive", true); if (_deferredActions != null) _deferredActions.Add(action); else action(); } public override void OnApplyTemplate() { //make sure the states get updated UpdateLargeState(); UpdateActiveState(); base.OnApplyTemplate(); if (_deferredActions != null) foreach (var action in _deferredActions) action(); _deferredActions = null; } } internal class WidthToMaxSideLengthConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { if (value is double) { var width = (double)value; return width <= 20 ? 20 : width; } return null; } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { throw new NotImplementedException(); } }
View Code

  样式代码:  

                                                
Visible
Visible
View Code

使用示例:  

IsActive

 

四.弹出异步等待框WaitingBox

  效果图:

 

  使用的是一个模式窗体,异步执行传入的操作,实现的比较简单,没有做异常处理。另外一个缺陷就是没有支持取消操作。后台C#代码:  

///     /// 简单等待框    ///     public partial class WaitingBox : Window    {        public string Text { get { return this.txtMessage.Text; } set { this.txtMessage.Text = value; } }        private Action _Callback;        public WaitingBox(Action callback)        {            InitializeComponent();            this._Callback = callback;            this.Loaded += WaitingBox_Loaded;        }        void WaitingBox_Loaded(object sender, RoutedEventArgs e)        {            this._Callback.BeginInvoke(this.OnComplate, null);        }        private void OnComplate(IAsyncResult ar)        {            this.Dispatcher.Invoke(new Action(() =>            {                this.Close();            }));        }        ///         /// 显示等待框,owner指定宿主视图元素,callback为需要执行的方法体(需要自己做异常处理)。        /// 目前等等框为模式窗体        ///         public static void Show(FrameworkElement owner, Action callback, string mes = "有一种幸福,叫做等待...")        {            WaitingBox win = new WaitingBox(callback);            Window pwin = Window.GetWindow(owner);            win.Owner = pwin;            win.Text = mes;            var loc = owner.PointToScreen(new Point());            win.Left = loc.X + (owner.ActualWidth - win.Width) / 2;            win.Top = loc.Y + (owner.ActualHeight - win.Height) / 2;            win.ShowDialog();        }    }

  样式代码:  

Loading...

  使用比较简单,示例:  

WaitingBox.Show(this, () =>            {                System.Threading.Thread.Sleep(3000);            },"正在玩命的加载,请稍后...");            var res = MessageBoxX.Question("已经完了?");

 

附录:参考引用 

 

版权所有,文章来源:

个人能力有限,本文内容仅供学习、探讨,欢迎指正、交流。

转载于:https://www.cnblogs.com/anding/p/5006279.html

你可能感兴趣的文章
187. Repeated DNA Sequences
查看>>
避免头文件重复包含
查看>>
Oracle:Authid Current_User的使用
查看>>
陈天桥:欣赏360保护隐私 用户安全永远第一
查看>>
JMeter使用技巧
查看>>
【Jump Game II 】cpp
查看>>
ubuntu 下 apache+tomcat整合_(mod-jk方法)[转]
查看>>
记录编译Hi3559A时遇到的一些错误和解决方法
查看>>
iis6 zencart1.39 伪静态规则
查看>>
Python学习之路7——深浅拷贝剖析
查看>>
宁波竞赛题
查看>>
Java实现Socket5代理服务器
查看>>
Android-异步图像装载机
查看>>
MySQL学习笔记——安装及配置环境
查看>>
SQL Server代理(3/12):代理警报和操作员
查看>>
android 物理按键 监听
查看>>
Do You Kown Asp.Net Core - 根据实体类自动创建Razor Page CURD页面模板
查看>>
npm 主要命令
查看>>
csrf攻击原理及如何防止csrf攻击
查看>>
C# Data Parse
查看>>