216 lines
7.8 KiB
C#
216 lines
7.8 KiB
C#
|
|
using System;
|
|||
|
|
using System.Collections.Generic;
|
|||
|
|
using System.Diagnostics;
|
|||
|
|
using System.Diagnostics.CodeAnalysis;
|
|||
|
|
using System.Linq;
|
|||
|
|
using System.Text;
|
|||
|
|
using System.Threading.Tasks;
|
|||
|
|
using System.Windows;
|
|||
|
|
using System.Windows.Controls;
|
|||
|
|
using System.Windows.Documents;
|
|||
|
|
using System.Windows.Input;
|
|||
|
|
using System.Windows.Media;
|
|||
|
|
|
|||
|
|
namespace Future.Contract
|
|||
|
|
{
|
|||
|
|
/// <summary>
|
|||
|
|
/// 加载遮罩:用于后台执行耗时加载任务时提供操作遮罩
|
|||
|
|
/// </summary>
|
|||
|
|
public class LoadingAdorner : Adorner
|
|||
|
|
{
|
|||
|
|
[AllowNull]
|
|||
|
|
private Grid _Layout;
|
|||
|
|
[AllowNull]
|
|||
|
|
private TextBlock _Feedback;
|
|||
|
|
[AllowNull]
|
|||
|
|
private AdornerLayer _AdornerLayer;
|
|||
|
|
[AllowNull]
|
|||
|
|
private VisualCollection _Visuals;
|
|||
|
|
|
|||
|
|
private Cursor _Cursor;
|
|||
|
|
|
|||
|
|
private System.Windows.Threading.DispatcherTimer _UiTimer = new System.Windows.Threading.DispatcherTimer();
|
|||
|
|
/// <summary>
|
|||
|
|
/// 对目标元素提供加载遮罩
|
|||
|
|
/// </summary>
|
|||
|
|
/// <param name="adornedElement">要进行遮盖的视觉元素</param>
|
|||
|
|
private LoadingAdorner(UIElement adornedElement) : base(adornedElement)
|
|||
|
|
{
|
|||
|
|
PrepareLoading();
|
|||
|
|
}
|
|||
|
|
private LoadingAdorner(UIElement adornedElement, string feedback, double progress = -1.1) : base(adornedElement)
|
|||
|
|
{
|
|||
|
|
PrepareLoading(feedback, progress);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 反馈信息
|
|||
|
|
/// </summary>
|
|||
|
|
public string Feedback
|
|||
|
|
{
|
|||
|
|
get { return (string)GetValue(FeedbackProperty); }
|
|||
|
|
set { SetValue(FeedbackProperty, value); Refresh(); }
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Using a DependencyProperty as the backing store for Feedback. This enables animation, styling, binding, etc...
|
|||
|
|
public static readonly DependencyProperty FeedbackProperty =
|
|||
|
|
DependencyProperty.Register("Feedback", typeof(string), typeof(LoadingAdorner), new PropertyMetadata("请稍等..."));
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 进度信息
|
|||
|
|
/// </summary>
|
|||
|
|
public double Progress
|
|||
|
|
{
|
|||
|
|
get { return (double)GetValue(ProgressProperty); }
|
|||
|
|
set { SetValue(ProgressProperty, value); Refresh(); }
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Using a DependencyProperty as the backing store for Progress. This enables animation, styling, binding, etc...
|
|||
|
|
public static readonly DependencyProperty ProgressProperty =
|
|||
|
|
DependencyProperty.Register("Progress", typeof(double), typeof(LoadingAdorner), new PropertyMetadata(-1.1));
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 准备启动:生成装饰器需要的内容
|
|||
|
|
/// </summary>
|
|||
|
|
/// <param name="feedback"></param>
|
|||
|
|
private void PrepareLoading(string feedback = "", double progress = -1.1)
|
|||
|
|
{
|
|||
|
|
_Visuals = new VisualCollection(this);
|
|||
|
|
_Layout = new Grid
|
|||
|
|
{
|
|||
|
|
Cursor = Cursors.Wait,
|
|||
|
|
ForceCursor = true
|
|||
|
|
};
|
|||
|
|
_Layout.Children.Add(new Border()
|
|||
|
|
{
|
|||
|
|
Background = Brushes.Gray,
|
|||
|
|
Opacity = 0.85,
|
|||
|
|
});
|
|||
|
|
_Feedback = new TextBlock()
|
|||
|
|
{
|
|||
|
|
Text = feedback,
|
|||
|
|
//FontSize=14,
|
|||
|
|
Foreground = Brushes.White,
|
|||
|
|
HorizontalAlignment = HorizontalAlignment.Center,
|
|||
|
|
VerticalAlignment = VerticalAlignment.Center,
|
|||
|
|
Margin = new Thickness(10)
|
|||
|
|
};
|
|||
|
|
_Layout.Children.Add(_Feedback);
|
|||
|
|
|
|||
|
|
_Visuals.Add(_Layout);
|
|||
|
|
|
|||
|
|
FeedbackProgress(feedback, progress);
|
|||
|
|
|
|||
|
|
_UiTimer.Interval = TimeSpan.FromMilliseconds(200);
|
|||
|
|
_UiTimer.Tick += (s, e) => Animate();
|
|||
|
|
_UiTimer.Start();
|
|||
|
|
|
|||
|
|
_AdornerLayer = AdornerLayer.GetAdornerLayer(AdornedElement);
|
|||
|
|
_AdornerLayer?.Add(this);
|
|||
|
|
|
|||
|
|
if (AdornedElement is FrameworkElement)
|
|||
|
|
{
|
|||
|
|
FrameworkElement target = (FrameworkElement)AdornedElement;
|
|||
|
|
_Cursor = target.Cursor;
|
|||
|
|
target.Cursor = Cursors.Wait;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
/// <summary>
|
|||
|
|
/// 开始装载:可以保证每个控件上方只会出现一个加载遮罩层
|
|||
|
|
/// </summary>
|
|||
|
|
/// <param name="adornedElement">加载目标</param>
|
|||
|
|
/// <param name="feedback">反馈信息</param>
|
|||
|
|
/// <param name="progress">进度信息</param>
|
|||
|
|
/// <returns>加载遮罩装饰器</returns>
|
|||
|
|
public static LoadingAdorner BeginLoading(UIElement adornedElement, string feedback = "", double progress = -1)
|
|||
|
|
{
|
|||
|
|
var adorners = AdornerLayer.GetAdornerLayer(adornedElement)?.GetAdorners(adornedElement)?.OfType<LoadingAdorner>();
|
|||
|
|
if (adorners != null && adorners.Count() == 1) return adorners.ToArray()[0];
|
|||
|
|
|
|||
|
|
return new LoadingAdorner(adornedElement, feedback, progress);
|
|||
|
|
}
|
|||
|
|
/// <summary>
|
|||
|
|
/// 结束加载:清除一个控件上方所有的加载遮罩层
|
|||
|
|
/// </summary>
|
|||
|
|
/// <param name="adornedElement">用标元素</param>
|
|||
|
|
public static void FinishLoading(UIElement adornedElement)
|
|||
|
|
{
|
|||
|
|
var adornerLayer = AdornerLayer.GetAdornerLayer(adornedElement);
|
|||
|
|
var adorners = adornerLayer?.GetAdorners(adornedElement);
|
|||
|
|
if (adorners == null) return;
|
|||
|
|
for (int i = adorners.Length - 1; i >= 0; i--)
|
|||
|
|
if (adorners[i] is LoadingAdorner)
|
|||
|
|
((LoadingAdorner)adorners[i]).Finish();
|
|||
|
|
}
|
|||
|
|
/// <summary>
|
|||
|
|
/// 进度反馈:用于向装饰器反馈当前进度
|
|||
|
|
/// </summary>
|
|||
|
|
/// <param name="feedback">信息:进度遮罩上显示的信息</param>
|
|||
|
|
/// <param name="progress">进度:0~1的小数,代表?%,其他数值无效</param>
|
|||
|
|
public void FeedbackProgress(string feedback = "", double progress = -1)
|
|||
|
|
{
|
|||
|
|
if (!string.IsNullOrEmpty(feedback)) Feedback = feedback;
|
|||
|
|
if (progress >= 0 && progress <= 1) Progress = progress;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private string _ProgressInfo = "请稍等...";
|
|||
|
|
/// <summary>
|
|||
|
|
/// 用于更新“进度信息”
|
|||
|
|
/// </summary>
|
|||
|
|
private void Refresh()
|
|||
|
|
{
|
|||
|
|
string prog = "-*-";
|
|||
|
|
if (0 <= Progress && Progress <= 1)
|
|||
|
|
prog = string.Format("{0:0%}", Progress).PadLeft(3);
|
|||
|
|
_ProgressInfo = $"[{prog}] : {Feedback.TrimEnd('.')} ... ";
|
|||
|
|
}
|
|||
|
|
/// <summary>
|
|||
|
|
/// 循环动画
|
|||
|
|
/// </summary>
|
|||
|
|
private void Animate()
|
|||
|
|
{
|
|||
|
|
string info = _Feedback.Text;
|
|||
|
|
if (!string.IsNullOrEmpty(info) && info.Length > 0)
|
|||
|
|
{
|
|||
|
|
char end = info[info.Length - 1];
|
|||
|
|
info = _ProgressInfo;
|
|||
|
|
|
|||
|
|
switch (end)
|
|||
|
|
{
|
|||
|
|
case '|': { info = info + '/'; } break;
|
|||
|
|
case '/': { info = info + '-'; } break;
|
|||
|
|
case '-': { info = info + '\\'; } break;
|
|||
|
|
case '\\': { info = info + '|'; } break;
|
|||
|
|
default: { info = info + '|'; } break;
|
|||
|
|
}
|
|||
|
|
_Feedback.Text = info;
|
|||
|
|
}
|
|||
|
|
else _Feedback.Text = _ProgressInfo + "|";
|
|||
|
|
}
|
|||
|
|
/// <summary>
|
|||
|
|
/// 结束装载
|
|||
|
|
/// </summary>
|
|||
|
|
public void Finish()
|
|||
|
|
{
|
|||
|
|
_UiTimer.Stop();
|
|||
|
|
|
|||
|
|
if (AdornedElement is FrameworkElement)
|
|||
|
|
{
|
|||
|
|
((FrameworkElement)AdornedElement).Cursor = _Cursor;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
_AdornerLayer?.Remove(this);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
protected override int VisualChildrenCount => _Visuals.Count;
|
|||
|
|
|
|||
|
|
protected override Visual GetVisualChild(int index) => _Visuals[index];
|
|||
|
|
|
|||
|
|
protected override Size ArrangeOverride(Size finalSize)
|
|||
|
|
{
|
|||
|
|
_Layout.Arrange(new Rect(new Point(0, 0), finalSize));
|
|||
|
|
return finalSize;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|