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
{
///
/// 加载遮罩:用于后台执行耗时加载任务时提供操作遮罩
///
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();
///
/// 对目标元素提供加载遮罩
///
/// 要进行遮盖的视觉元素
private LoadingAdorner(UIElement adornedElement) : base(adornedElement)
{
PrepareLoading();
}
private LoadingAdorner(UIElement adornedElement, string feedback, double progress = -1.1) : base(adornedElement)
{
PrepareLoading(feedback, progress);
}
///
/// 反馈信息
///
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("请稍等..."));
///
/// 进度信息
///
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));
///
/// 准备启动:生成装饰器需要的内容
///
///
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;
}
}
///
/// 开始装载:可以保证每个控件上方只会出现一个加载遮罩层
///
/// 加载目标
/// 反馈信息
/// 进度信息
/// 加载遮罩装饰器
public static LoadingAdorner BeginLoading(UIElement adornedElement, string feedback = "", double progress = -1)
{
var adorners = AdornerLayer.GetAdornerLayer(adornedElement)?.GetAdorners(adornedElement)?.OfType();
if (adorners != null && adorners.Count() == 1) return adorners.ToArray()[0];
return new LoadingAdorner(adornedElement, feedback, progress);
}
///
/// 结束加载:清除一个控件上方所有的加载遮罩层
///
/// 用标元素
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();
}
///
/// 进度反馈:用于向装饰器反馈当前进度
///
/// 信息:进度遮罩上显示的信息
/// 进度:0~1的小数,代表?%,其他数值无效
public void FeedbackProgress(string feedback = "", double progress = -1)
{
if (!string.IsNullOrEmpty(feedback)) Feedback = feedback;
if (progress >= 0 && progress <= 1) Progress = progress;
}
private string _ProgressInfo = "请稍等...";
///
/// 用于更新“进度信息”
///
private void Refresh()
{
string prog = "-*-";
if (0 <= Progress && Progress <= 1)
prog = string.Format("{0:0%}", Progress).PadLeft(3);
_ProgressInfo = $"[{prog}] : {Feedback.TrimEnd('.')} ... ";
}
///
/// 循环动画
///
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 + "|";
}
///
/// 结束装载
///
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;
}
}
}