将以往的代码复制到代码库
This commit is contained in:
106
Future.Contract/Adorners/DragDropAdorner.cs
Normal file
106
Future.Contract/Adorners/DragDropAdorner.cs
Normal file
@@ -0,0 +1,106 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Documents;
|
||||
using System.Windows.Media;
|
||||
|
||||
namespace Future.Contract
|
||||
{
|
||||
/// <summary>
|
||||
/// 拖动辅助装饰器
|
||||
/// </summary>
|
||||
public class DragDropAdorner : Adorner
|
||||
{
|
||||
#region 静态变量区
|
||||
private static DragDropAdorner sAdorner; //装饰器:拖放过程中所有效果绘制使用的装饰器对象,结束后会释放
|
||||
private static AdornerLayer sLayer; //装饰层:用于放置拖放效果装饰器,拖放过程结束后会清除对象引用
|
||||
|
||||
private static UIElement sOrigin; //拖起目标:被拖动的源对象
|
||||
private static UIElement sTarget; //放置目标:在拖动过程中用于放置拖动源的目标,随拖动过程而变化
|
||||
|
||||
private static Canvas sCanvas; //拖放画布:整个拖放过程的完整区域,是拖起目标与放置目标的祖辈
|
||||
private static Border sShadow; //鼠标拖起阴影:用于将托起目标尺寸按照相同缩放比缩放后变成阴影
|
||||
private static Canvas sEffect; //鼠标拖动效果:用于提示放置的参考点位置,左、上、右、下,中。
|
||||
|
||||
private static Dock sPosition; //参考放置位置:为放置目标的位置提供参考,左、上、右、下,中。
|
||||
|
||||
/// <summary>
|
||||
/// 放置的参考点
|
||||
/// </summary>
|
||||
public static Dock DropPosition { get => sPosition; }
|
||||
#endregion
|
||||
#region 静态方法区
|
||||
/// <summary>
|
||||
/// 设定完整拖放效果区域以及被拖动的对象,或是等效对象来起动拖放事件
|
||||
/// </summary>
|
||||
/// <param name="area">完整的拖放区域,必须是拖起目标与放置目标的共同祖先节点</param>
|
||||
/// <param name="origin">被拖动的可视化目标,或是其等效目标</param>
|
||||
/// <returns></returns>
|
||||
public static DragDropEffects DoDragDrop(UIElement area, UIElement dragSource, object data, DragDropEffects allowedEffects)
|
||||
{
|
||||
DragDropEffects dragDropEffects = allowedEffects;
|
||||
//TODO:准备拖放,生成阴影,监听拖动执行区域中的拖动事件
|
||||
dragDropEffects = DragDrop.DoDragDrop(dragSource, data, dragDropEffects);
|
||||
//TODO:拖拽操作完成,释放装饰器以及过程中使用的所有资源
|
||||
sLayer.Remove(sAdorner);
|
||||
return dragDropEffects;
|
||||
}
|
||||
|
||||
private static void OnDragEnter(UIElement target, DragEventArgs args)
|
||||
{
|
||||
sTarget= target;
|
||||
target.MouseMove += Target_MouseMove;
|
||||
//TODO:更换目标对象,监听目标对象的鼠标事件,规制“阴影”与“效果”
|
||||
}
|
||||
|
||||
private static void Target_MouseMove(object sender, System.Windows.Input.MouseEventArgs e)
|
||||
{
|
||||
//TODO:计算鼠标位置,移动效果与阴影
|
||||
}
|
||||
//public static void OnDragOver(UIElement target, DragEventArgs args)
|
||||
//{
|
||||
// //TODO:计算鼠标位置,移动效果与阴影
|
||||
//}
|
||||
public static void OnDragLeave(UIElement target, DragEventArgs args)
|
||||
{
|
||||
//TODO:清除目标对象,清除对鼠标事件的监听,清除“阴影”与“效果”
|
||||
target.MouseMove -= Target_MouseMove;
|
||||
}
|
||||
public static void DropCompleted(UIElement target, DragEventArgs args)
|
||||
{
|
||||
//TODO:清除静态存储区中所使用过的数据,清除装饰器
|
||||
}
|
||||
#endregion
|
||||
private readonly VisualCollection mVisuals;
|
||||
private DragDropAdorner(UIElement adornedElement) : base(adornedElement)
|
||||
{
|
||||
mVisuals = new VisualCollection(this);
|
||||
sCanvas = new Canvas
|
||||
{
|
||||
Background=Brushes.Transparent
|
||||
};
|
||||
|
||||
mVisuals.Add(sCanvas);
|
||||
sLayer = AdornerLayer.GetAdornerLayer(adornedElement);
|
||||
sLayer?.Add(this);
|
||||
}
|
||||
|
||||
protected override int VisualChildrenCount => mVisuals.Count;
|
||||
|
||||
protected override Visual GetVisualChild(int index) => mVisuals[index];
|
||||
|
||||
protected override Size ArrangeOverride(Size finalSize)
|
||||
{
|
||||
//var bubbleSize = _bubble.DesiredSize;
|
||||
//var location = new Point(finalSize.Width + 10, (finalSize.Height - bubbleSize.Height) / 2);
|
||||
//_bubble.Arrange(new Rect(location, DesiredSize));
|
||||
sCanvas.Arrange(new Rect(new Point(), finalSize));
|
||||
return finalSize;
|
||||
}
|
||||
}
|
||||
}
|
||||
290
Future.Contract/Adorners/DrawerAdorner.cs
Normal file
290
Future.Contract/Adorners/DrawerAdorner.cs
Normal file
@@ -0,0 +1,290 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows;
|
||||
using System.Windows.Documents;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Animation;
|
||||
|
||||
namespace Future.Contract
|
||||
{
|
||||
public sealed class DrawerAdorner : Adorner
|
||||
{
|
||||
private VisualCollection mVisuals;
|
||||
private Border mRoot;
|
||||
private AdornerLayer? mLayer;
|
||||
private Size mSize;
|
||||
private bool mIsShowed = false;
|
||||
private bool mIsClosed = false;
|
||||
private Func<bool> mApplyCloseCallback;
|
||||
|
||||
public DrawerAdorner(UIElement adornedElement) : base(adornedElement)
|
||||
{
|
||||
mVisuals = new VisualCollection(this);
|
||||
mRoot = new Border();
|
||||
mVisuals.Add(mRoot);
|
||||
|
||||
this.mLayer = AdornerLayer.GetAdornerLayer(adornedElement);
|
||||
//注意:开场动画必须在此处执行
|
||||
this.Loaded += (ss, ee) => this.StartAnimationIn();
|
||||
//this.Unloaded += (ss, ee) => this.StartAnimationOut();
|
||||
}
|
||||
|
||||
protected override int VisualChildrenCount => mVisuals.Count;
|
||||
|
||||
protected override Visual GetVisualChild(int index) => mVisuals[index];
|
||||
|
||||
protected override Size ArrangeOverride(Size finalSize)
|
||||
{
|
||||
mSize = finalSize;
|
||||
mRoot.Arrange(new Rect(new Point(), finalSize));
|
||||
|
||||
return finalSize;
|
||||
}
|
||||
#pragma warning disable CS0628 // 在密封类型中声明了新的保护成员
|
||||
protected void SetHandleVisibility(Visibility visibility)
|
||||
#pragma warning restore CS0628 // 在密封类型中声明了新的保护成员
|
||||
{
|
||||
if (this.mRoot.Child != null && this.mRoot.Child is DrawerTemplate)
|
||||
{
|
||||
DrawerTemplate template = this.mRoot.Child as DrawerTemplate;
|
||||
template.HandleVisibility = visibility;
|
||||
}
|
||||
}
|
||||
public void ShowWithTemplate(DrawerTemplate? template, FrameworkElement view, string title, Func<bool>? applyCloseCallback = null)
|
||||
{
|
||||
if (template == null && view == null) return;
|
||||
view?.ClearValue(FrameworkElement.WidthProperty);
|
||||
view?.ClearValue(FrameworkElement.HeightProperty);
|
||||
this.mApplyCloseCallback = applyCloseCallback;
|
||||
if (template != null)
|
||||
{
|
||||
this.mRoot.Child = template;
|
||||
template.Title = title;
|
||||
template.Content = view;
|
||||
template.ApplyCloseDrawer += () => this.Close();
|
||||
}
|
||||
else this.mRoot.Child = view;
|
||||
|
||||
//隐藏同一个目标上最上层的相同装饰器的半透明区域(注意:需要防止这个逻辑执行2次)
|
||||
var adorners = this.mLayer?.GetAdorners(this.AdornedElement);
|
||||
if (adorners != null && !this.mIsShowed)//保证即使更换显示内容也不会重复处理关闭按钮的隐藏
|
||||
{
|
||||
for (int i = adorners.Length - 1; i >= 0; i--)
|
||||
if (adorners[i] is DrawerAdorner)
|
||||
{
|
||||
((DrawerAdorner)adorners[i]).SetHandleVisibility(Visibility.Collapsed);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!this.mIsShowed) this.mLayer?.Add(this);//完成显示工作
|
||||
//注意:入场动画在OnLoad事件的响应时调用
|
||||
this.mIsShowed = true;
|
||||
this.mIsClosed = false;
|
||||
}
|
||||
|
||||
public static DrawerAdorner ShowInVisual(UIElement adornedElement, DrawerTemplate? template, FrameworkElement view, string title, Func<bool>? applyCloseCallback = null)
|
||||
{
|
||||
DrawerAdorner drawer = new DrawerAdorner(adornedElement);
|
||||
drawer.ShowWithTemplate(template?.Clone(), view, title, applyCloseCallback);
|
||||
//drawer.ShowWithTemplate(template, view, title, applyCloseCallback);
|
||||
return drawer;
|
||||
}
|
||||
|
||||
public static DrawerAdorner ShowInTarget(string targetName, DrawerTemplate? template, FrameworkElement view, string title, Func<bool>? applyCloseCallback = null)
|
||||
{
|
||||
if (LayerOwners.ContainsKey(targetName))
|
||||
return ShowInVisual(LayerOwners[targetName], template, view, title, applyCloseCallback);
|
||||
else return null;
|
||||
}
|
||||
|
||||
public void ShowOnlyView(FrameworkElement view) => this.ShowWithTemplate(null, view, null, null);
|
||||
|
||||
public static DrawerAdorner ShowView(UIElement adornedElement, FrameworkElement view)
|
||||
{
|
||||
DrawerAdorner drawer = new DrawerAdorner(adornedElement);
|
||||
drawer.ShowOnlyView(view);
|
||||
return drawer;
|
||||
}
|
||||
|
||||
public void CloseDrawer()
|
||||
{
|
||||
//强制清空请求关闭委托
|
||||
this.mApplyCloseCallback = null;
|
||||
this.Close();
|
||||
}
|
||||
|
||||
private async void Close()
|
||||
{
|
||||
if (this.mIsClosed) return;//如果已经关闭了就不要重复执行了,会导致层叠问题
|
||||
var sign = this.mApplyCloseCallback?.Invoke();
|
||||
if (sign == false) return;
|
||||
|
||||
#region 关闭动画;注意:不能单独封装为函数使用,否则会因为“异步”执行造成动画失效;如果单独封装成函数则需要将“装饰器”卸载操作一同封装
|
||||
float seconds = 0.3f;
|
||||
var sb = new Storyboard();
|
||||
//var offset = mRoot?.ActualWidth ?? 0;
|
||||
//var animation = new ThicknessAnimation
|
||||
//{
|
||||
// Duration = new Duration(TimeSpan.FromSeconds(seconds)),
|
||||
// From = new Thickness(0),
|
||||
// To = new Thickness(-offset, 0, offset, 0),
|
||||
//};
|
||||
var animation = BuildAnimation(seconds, true);
|
||||
Storyboard.SetTargetProperty(animation, new PropertyPath("Margin"));
|
||||
sb.Children.Add(animation);
|
||||
sb.Begin(mRoot);
|
||||
await Task.Delay((int)(seconds * 1000));
|
||||
#endregion
|
||||
|
||||
//开始卸载装饰器
|
||||
this.SetHandleVisibility(Visibility.Collapsed);
|
||||
this.mRoot.Child = null; //清除模板视图的引用
|
||||
this.mLayer?.Remove(this); //完成关闭装饰器工作
|
||||
//显示同一个目标上最上层的相同装饰器的半透明区域
|
||||
var adorners = this.mLayer?.GetAdorners(this.AdornedElement);
|
||||
if (adorners != null)
|
||||
{
|
||||
for (int i = adorners.Length - 1; i >= 0; i--)
|
||||
if (adorners[i] is DrawerAdorner)
|
||||
{
|
||||
((DrawerAdorner)adorners[i]).SetHandleVisibility(Visibility.Visible);
|
||||
break;
|
||||
}
|
||||
}
|
||||
this.mIsClosed = true;
|
||||
this.mIsShowed = false;
|
||||
}
|
||||
private ThicknessAnimation BuildAnimation(float seconds = 0.3f, bool inOrOut = false)
|
||||
{
|
||||
var wOffset = mRoot?.ActualWidth ?? 0;
|
||||
var hOffset = mRoot?.ActualHeight ?? 0;
|
||||
|
||||
Thickness from = new Thickness(-wOffset, 0, wOffset, 0);
|
||||
Thickness to = new Thickness(0);
|
||||
|
||||
DrawerTemplate template = this.mRoot?.Child as DrawerTemplate;
|
||||
if (template != null)
|
||||
{
|
||||
switch (template.Dock)
|
||||
{
|
||||
case Dock.Top:
|
||||
from = new Thickness(0, -hOffset, 0, hOffset);
|
||||
break;
|
||||
case Dock.Bottom:
|
||||
from = new Thickness(0, hOffset, 0, -hOffset);
|
||||
break;
|
||||
case Dock.Right:
|
||||
from = new Thickness(wOffset, 0, -wOffset, 0);
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
//如果是退出动画则需要对调From与To两个节点
|
||||
if (inOrOut)
|
||||
{
|
||||
Thickness thickness = from;
|
||||
from = to;
|
||||
to = thickness;
|
||||
}
|
||||
|
||||
return new ThicknessAnimation()
|
||||
{
|
||||
Duration = new Duration(TimeSpan.FromSeconds(seconds)),
|
||||
From = from,
|
||||
To = to
|
||||
};
|
||||
}
|
||||
private async void StartAnimationIn(float seconds = 0.3f)
|
||||
{
|
||||
var sb = new Storyboard();
|
||||
//var offset = mRoot?.ActualWidth ?? 0;
|
||||
//var animation = new ThicknessAnimation
|
||||
//{
|
||||
// Duration = new Duration(TimeSpan.FromSeconds(seconds)),
|
||||
// From = new Thickness(-offset, 0, offset, 0),
|
||||
// To = new Thickness(0)
|
||||
//};
|
||||
var animation = BuildAnimation(seconds);
|
||||
Storyboard.SetTargetProperty(animation, new PropertyPath("Margin"));
|
||||
sb.Children.Add(animation);
|
||||
sb.Begin(mRoot);
|
||||
await Task.Delay((int)(seconds * 1000));
|
||||
}
|
||||
private async void StartAnimationOut(float seconds = 0.3f)
|
||||
{
|
||||
var sb = new Storyboard();
|
||||
var offset = mRoot?.ActualWidth ?? 0;
|
||||
var animation = new ThicknessAnimation
|
||||
{
|
||||
Duration = new Duration(TimeSpan.FromSeconds(seconds)),
|
||||
From = new Thickness(0),
|
||||
To = new Thickness(-offset, 0, offset, 0),
|
||||
};
|
||||
Storyboard.SetTargetProperty(animation, new PropertyPath("Margin"));
|
||||
sb.Children.Add(animation);
|
||||
sb.Begin(mRoot);
|
||||
await Task.Delay((int)(seconds * 1000));
|
||||
|
||||
this.mRoot.Child = null;
|
||||
this.mLayer?.Remove(this);//完成关闭工作
|
||||
//显示同一个目标上最上层的相同装饰器的半透明区域
|
||||
var adorners = this.mLayer?.GetAdorners(this.AdornedElement);
|
||||
if (adorners != null)
|
||||
{
|
||||
for (int i = adorners.Length - 1; i >= 0; i--)
|
||||
if (adorners[i] is DrawerAdorner)
|
||||
{
|
||||
((DrawerAdorner)adorners[i]).SetHandleVisibility(Visibility.Visible);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#region 依赖属性
|
||||
private static Dictionary<string, UIElement> LayerOwners = new Dictionary<string, UIElement>();
|
||||
public static string GetLayerName(DependencyObject obj)
|
||||
{
|
||||
return (string)obj.GetValue(LayerNameProperty);
|
||||
}
|
||||
public static void SetLayerName(DependencyObject obj, string value)
|
||||
{
|
||||
obj.SetValue(LayerNameProperty, value);
|
||||
}
|
||||
// Using a DependencyProperty as the backing store for LayerName. This enables animation, styling, binding, etc...
|
||||
public static readonly DependencyProperty LayerNameProperty =
|
||||
DependencyProperty.RegisterAttached("LayerName", typeof(string), typeof(DrawerAdorner), new PropertyMetadata(null, (s, e) =>
|
||||
{
|
||||
//将抽屉拥有者注册到静态区
|
||||
var layerOwner = s as UIElement;
|
||||
if (s == null) return;
|
||||
if (e.OldValue != null && LayerOwners.ContainsKey((string)e.OldValue))
|
||||
LayerOwners.Remove((string)e.OldValue);
|
||||
if (e.NewValue != null && layerOwner != null)
|
||||
{
|
||||
if (LayerOwners.ContainsKey((string)e.NewValue))
|
||||
LayerOwners.Remove((string)e.NewValue);
|
||||
|
||||
LayerOwners.Add((string)e.NewValue, layerOwner);
|
||||
|
||||
DependencyObject d = s;
|
||||
while (d != null)
|
||||
{
|
||||
if (d is Window) break;
|
||||
var f = d as FrameworkElement;
|
||||
if (f != null && f is not Window) d = f.Parent;
|
||||
}
|
||||
if (d is Window)
|
||||
{
|
||||
Window w = (Window)d;
|
||||
w.Unloaded += (ss, ee) =>
|
||||
LayerOwners.Remove((string)e.NewValue);
|
||||
}
|
||||
}
|
||||
}));
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
119
Future.Contract/Adorners/DrawerTemplate.cs
Normal file
119
Future.Contract/Adorners/DrawerTemplate.cs
Normal file
@@ -0,0 +1,119 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
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 Future.Contract
|
||||
{
|
||||
[TemplatePart(Name = "CloseHandle", Type = typeof(Button))] //关闭按钮
|
||||
//[TemplatePart(Name = "OpacityArea", Type = typeof(UIElement))] //透视区域
|
||||
public class DrawerTemplate : ContentControl
|
||||
{
|
||||
private Button? _CloseHandle;
|
||||
//private UIElement? _OpacityArea;
|
||||
static DrawerTemplate()
|
||||
{
|
||||
DefaultStyleKeyProperty.OverrideMetadata(typeof(DrawerTemplate), new FrameworkPropertyMetadata(typeof(DrawerTemplate)));
|
||||
}
|
||||
/// <summary>
|
||||
/// 请求关闭事件
|
||||
/// </summary>
|
||||
public event Action? ApplyCloseDrawer;
|
||||
|
||||
public override void OnApplyTemplate()
|
||||
{
|
||||
base.OnApplyTemplate();
|
||||
this._CloseHandle = this.Template.FindName("CloseHandle", this) as Button;
|
||||
//this._OpacityArea = this.Template.FindName("OpacityArea", this) as UIElement;
|
||||
if (this._CloseHandle != null) this._CloseHandle.Click += (s, e) => this.ApplyCloseDrawer?.Invoke();
|
||||
}
|
||||
|
||||
public DrawerTemplate Clone()
|
||||
{
|
||||
return new DrawerTemplate()
|
||||
{
|
||||
Background = this.Background,
|
||||
Foreground = this.Foreground,
|
||||
BorderBrush = this.BorderBrush,
|
||||
BorderThickness = this.BorderThickness,
|
||||
HorizontalAlignment = this.HorizontalAlignment,
|
||||
VerticalAlignment = this.VerticalAlignment,
|
||||
HorizontalContentAlignment = this.HorizontalContentAlignment,
|
||||
VerticalContentAlignment = this.VerticalContentAlignment,
|
||||
Dock = this.Dock,
|
||||
FontFamily = this.FontFamily,
|
||||
FontSize = this.FontSize,
|
||||
FontStretch=this.FontStretch,
|
||||
FontStyle = this.FontStyle,
|
||||
FontWeight = this.FontWeight,
|
||||
//Template = this.Template,
|
||||
Style = this.Style
|
||||
};
|
||||
}
|
||||
|
||||
#region 依赖属性
|
||||
|
||||
/// <summary>
|
||||
/// 抽屉标题
|
||||
/// </summary>
|
||||
public string Title
|
||||
{
|
||||
get { return (string)GetValue(TitleProperty); }
|
||||
set { SetValue(TitleProperty, value); }
|
||||
}
|
||||
|
||||
// Using a DependencyProperty as the backing store for Title. This enables animation, styling, binding, etc...
|
||||
public static readonly DependencyProperty TitleProperty =
|
||||
DependencyProperty.Register("Title", typeof(string), typeof(DrawerTemplate), new PropertyMetadata(""));
|
||||
|
||||
/// <summary>
|
||||
/// 停靠方向
|
||||
/// </summary>
|
||||
public Dock Dock
|
||||
{
|
||||
get { return (Dock)GetValue(DockProperty); }
|
||||
set { SetValue(DockProperty, value); }
|
||||
}
|
||||
|
||||
// Using a DependencyProperty as the backing store for Dock. This enables animation, styling, binding, etc...
|
||||
public static readonly DependencyProperty DockProperty =
|
||||
DependencyProperty.Register("Dock", typeof(Dock), typeof(DrawerTemplate), new PropertyMetadata(Dock.Right));
|
||||
|
||||
public Visibility HandleVisibility
|
||||
{
|
||||
get { return (Visibility)GetValue(HandleVisibilityProperty); }
|
||||
set { SetValue(HandleVisibilityProperty, value); }
|
||||
}
|
||||
|
||||
// Using a DependencyProperty as the backing store for HandleVisibility. This enables animation, styling, binding, etc...
|
||||
public static readonly DependencyProperty HandleVisibilityProperty =
|
||||
DependencyProperty.Register("HandleVisibility", typeof(Visibility), typeof(DrawerTemplate), new PropertyMetadata(Visibility.Visible));
|
||||
|
||||
|
||||
|
||||
public double TitleHeight
|
||||
{
|
||||
get { return (double)GetValue(TitleHeightProperty); }
|
||||
set { SetValue(TitleHeightProperty, value); }
|
||||
}
|
||||
|
||||
// Using a DependencyProperty as the backing store for TitleHeight. This enables animation, styling, binding, etc...
|
||||
public static readonly DependencyProperty TitleHeightProperty =
|
||||
DependencyProperty.Register("TitleHeight", typeof(double), typeof(DrawerTemplate), new PropertyMetadata(60.0));
|
||||
|
||||
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
366
Future.Contract/Adorners/FutureDrawer.cs
Normal file
366
Future.Contract/Adorners/FutureDrawer.cs
Normal file
@@ -0,0 +1,366 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
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.Animation;
|
||||
using System.Windows.Media.Imaging;
|
||||
using System.Windows.Navigation;
|
||||
using System.Windows.Shapes;
|
||||
|
||||
namespace Future.Contract
|
||||
{
|
||||
/// <summary>
|
||||
/// [Content]属性就是抽屉中要呈现的视图
|
||||
/// <MyNamespace:FutureDrawer/>
|
||||
/// </summary>
|
||||
[TemplatePart(Name = "TitleBorder", Type = typeof(Border))]//执行透明度动画
|
||||
[TemplatePart(Name = "ContentView", Type = typeof(Border))]//执行Margin动画
|
||||
[TemplatePart(Name = "CloseHandle", Type = typeof(Button))]//执行透明度动化
|
||||
[TemplatePart(Name = "DrawerRoot", Type = typeof(DockPanel))]//处理窗口最大化时的边距
|
||||
public class FutureDrawer : ContentControl
|
||||
{
|
||||
static FutureDrawer()
|
||||
{
|
||||
DefaultStyleKeyProperty.OverrideMetadata(typeof(FutureDrawer), new FrameworkPropertyMetadata(typeof(FutureDrawer)));
|
||||
}
|
||||
|
||||
#region 抽屉动画
|
||||
private const string TitleBorder = "TitleBorder";
|
||||
private const string ContentView = "ContentView";
|
||||
private const string CloseButton = "CloseHandle";
|
||||
private const string DrawerRoot = "DrawerRoot";
|
||||
|
||||
private Border mContentView;
|
||||
private Button mCloseButton;
|
||||
private DockPanel mDrawerRoot;
|
||||
public override void OnApplyTemplate()
|
||||
{
|
||||
base.OnApplyTemplate();
|
||||
mContentView = GetTemplateChild(ContentView) as Border;
|
||||
mCloseButton = GetTemplateChild(CloseButton) as Button;
|
||||
mDrawerRoot = GetTemplateChild(DrawerRoot) as DockPanel;
|
||||
if (mCloseButton != null) mCloseButton.Click += (s, e) =>
|
||||
{
|
||||
if(this.ApplyCloseDrawer != null && !this.ApplyCloseDrawer(this.Sign)) return;
|
||||
else IsOpen = false;
|
||||
};
|
||||
this.Loaded += (s, e) => IsOpen = true;
|
||||
}
|
||||
|
||||
public bool IsOpen
|
||||
{
|
||||
get { return (bool)GetValue(IsOpenProperty); }
|
||||
set { SetValue(IsOpenProperty, value); }
|
||||
}
|
||||
public static readonly DependencyProperty IsOpenProperty =
|
||||
DependencyProperty.Register("IsOpen", typeof(bool), typeof(FutureDrawer), new PropertyMetadata(false, (s, e) =>
|
||||
{
|
||||
var drawer = s as FutureDrawer;
|
||||
if (e.NewValue is bool b && b)
|
||||
{
|
||||
drawer?.StartAnimationIn();
|
||||
}
|
||||
else
|
||||
{
|
||||
drawer?.StartAnimationOut();
|
||||
}
|
||||
}));
|
||||
|
||||
|
||||
private async void StartAnimationIn(float seconds = 0.3f)
|
||||
{
|
||||
var sb = new Storyboard();
|
||||
var offset = mDrawerRoot?.ActualWidth ?? 0;
|
||||
var animation = new ThicknessAnimation
|
||||
{
|
||||
Duration = new Duration(TimeSpan.FromSeconds(seconds)),
|
||||
From = new Thickness(-offset, 0, offset, 0),
|
||||
To = new Thickness(0)
|
||||
};
|
||||
Storyboard.SetTargetProperty(animation, new PropertyPath("Margin"));
|
||||
sb.Children.Add(animation);
|
||||
sb.Begin(mDrawerRoot);
|
||||
await Task.Delay((int)(seconds * 1000));
|
||||
|
||||
}
|
||||
private async void StartAnimationOut(float seconds = 0.3f)
|
||||
{
|
||||
var sb = new Storyboard();
|
||||
var offset = mDrawerRoot?.ActualWidth ?? 0;
|
||||
var animation = new ThicknessAnimation
|
||||
{
|
||||
Duration = new Duration(TimeSpan.FromSeconds(seconds)),
|
||||
From = new Thickness(0),
|
||||
To = new Thickness(-offset, 0, offset, 0),
|
||||
};
|
||||
Storyboard.SetTargetProperty(animation, new PropertyPath("Margin"));
|
||||
sb.Children.Add(animation);
|
||||
sb.Begin(mDrawerRoot);
|
||||
await Task.Delay((int)(seconds * 1000));
|
||||
|
||||
this.DrawerClosed?.Invoke();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public Dock Dock
|
||||
{
|
||||
get { return (Dock)GetValue(DockProperty); }
|
||||
set { SetValue(DockProperty, value); }
|
||||
}
|
||||
|
||||
// Using a DependencyProperty as the backing store for Dock. This enables animation, styling, binding, etc...
|
||||
public static readonly DependencyProperty DockProperty =
|
||||
DependencyProperty.Register("Dock", typeof(Dock), typeof(FutureDrawer), new PropertyMetadata(Dock.Right));
|
||||
|
||||
|
||||
|
||||
public double TitleHeight
|
||||
{
|
||||
get { return (double)GetValue(TitleHeightProperty); }
|
||||
set { SetValue(TitleHeightProperty, value); }
|
||||
}
|
||||
|
||||
// Using a DependencyProperty as the backing store for TitleHeight. This enables animation, styling, binding, etc...
|
||||
public static readonly DependencyProperty TitleHeightProperty =
|
||||
DependencyProperty.Register("TitleHeight", typeof(double), typeof(FutureDrawer), new PropertyMetadata(40.0));
|
||||
|
||||
|
||||
|
||||
public double TitleIndent
|
||||
{
|
||||
get { return (double)GetValue(TitleIndentProperty); }
|
||||
set { SetValue(TitleIndentProperty, value); }
|
||||
}
|
||||
|
||||
// Using a DependencyProperty as the backing store for TitleIndent. This enables animation, styling, binding, etc...
|
||||
public static readonly DependencyProperty TitleIndentProperty =
|
||||
DependencyProperty.Register("TitleIndent", typeof(double), typeof(FutureDrawer), new PropertyMetadata(0.0));
|
||||
|
||||
|
||||
|
||||
public string Title
|
||||
{
|
||||
get { return (string)GetValue(TitleProperty); }
|
||||
set { SetValue(TitleProperty, value); }
|
||||
}
|
||||
|
||||
// Using a DependencyProperty as the backing store for Title. This enables animation, styling, binding, etc...
|
||||
public static readonly DependencyProperty TitleProperty =
|
||||
DependencyProperty.Register("Title", typeof(string), typeof(FutureDrawer), new PropertyMetadata(""));
|
||||
|
||||
public int? Sign
|
||||
{
|
||||
get { return (int?)GetValue(SignProperty); }
|
||||
set { SetValue(SignProperty, value); }
|
||||
}
|
||||
|
||||
// Using a DependencyProperty as the backing store for Sign. This enables animation, styling, binding, etc...
|
||||
public static readonly DependencyProperty SignProperty =
|
||||
DependencyProperty.Register("Sign", typeof(int?), typeof(FutureDrawer), new PropertyMetadata(0));
|
||||
|
||||
/// <summary>
|
||||
/// 当抽屉准备关闭时发出的申请
|
||||
/// </summary>
|
||||
public event Func<int?, bool> ApplyCloseDrawer;
|
||||
/// <summary>
|
||||
/// 抽屉关闭后发出通知的委托
|
||||
/// </summary>
|
||||
public Action DrawerClosed;
|
||||
/// <summary>
|
||||
/// 默认构造:用来使用设计器构造抽屉模板
|
||||
/// </summary>
|
||||
public FutureDrawer() { }
|
||||
public void Close()
|
||||
{
|
||||
this.StartAnimationOut();
|
||||
}
|
||||
/// <summary>
|
||||
/// 内部构造:用来复刻当前抽屉模板创建新的抽屉来显示内容
|
||||
/// </summary>
|
||||
/// <param name="view">要呈现的视图</param>
|
||||
/// <param name="title">抽屉的标题</param>
|
||||
/// <param name="callBackSign">用于CallBack的识别码</param>
|
||||
/// <param name="applyCloseCallBack">抽屉要关闭时的回调通知</param>
|
||||
private FutureDrawer(UIElement view, string title, int? callBackSign = null, Func<int?, bool> applyCloseCallBack = null)
|
||||
{
|
||||
this.Content = view;
|
||||
this.Title = title;
|
||||
this.Sign = Sign;
|
||||
this.ApplyCloseDrawer = applyCloseCallBack;
|
||||
}
|
||||
/// <summary>
|
||||
/// 克隆当前抽屉的所有属性
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private FutureDrawer Clone(UIElement view, string title, int? callBackSign = null, Func<int?, bool> applyCloseCallBack = null)
|
||||
{
|
||||
FutureDrawer result = new FutureDrawer(view, title, callBackSign, applyCloseCallBack);
|
||||
result.Dock = this.Dock;
|
||||
result.TitleHeight = this.TitleHeight;
|
||||
result.TitleIndent = this.TitleIndent;
|
||||
result.Background = this.Background;
|
||||
result.Foreground = this.Foreground;
|
||||
result.Margin = this.Margin;
|
||||
result.HorizontalAlignment = this.HorizontalAlignment;
|
||||
result.VerticalAlignment = this.VerticalAlignment;
|
||||
result.HorizontalContentAlignment = this.HorizontalContentAlignment;
|
||||
result.VerticalContentAlignment = this.VerticalContentAlignment;
|
||||
result.FontSize = this.FontSize;
|
||||
|
||||
return result;
|
||||
}
|
||||
private Window GetWindow(FrameworkElement origin)
|
||||
{
|
||||
if (origin == null) return null;
|
||||
while (origin != null && origin is not Window) origin = origin.Parent as FrameworkElement;
|
||||
return origin as Window;
|
||||
}
|
||||
/// <summary>
|
||||
/// 抽屉使用的装饰器,如果存在则证明抽屉曾经打开过,不需要重复创建
|
||||
/// </summary>
|
||||
private DrawerAdorner _adorner;
|
||||
/// <summary>
|
||||
/// 将当前抽屉显示在目标UIElement【target】中
|
||||
/// </summary>
|
||||
/// <param name="target">要显示当前抽屉的UIElement元素</param>
|
||||
public void ShowInTarget(FrameworkElement target, object content = null)
|
||||
{
|
||||
this.Content = content ?? this.Content;
|
||||
Window window = GetWindow(target);
|
||||
if (window != null)
|
||||
{
|
||||
if (window.WindowState == WindowState.Maximized) this.Padding = new Thickness(8);
|
||||
window.StateChanged += (s, e) =>
|
||||
{
|
||||
Window w = s as Window;
|
||||
if (w != null)
|
||||
{
|
||||
if (w.WindowState == WindowState.Maximized)
|
||||
this.Padding = new Thickness(8);
|
||||
else this.Padding = new Thickness(0);
|
||||
}
|
||||
};
|
||||
}
|
||||
//TODO:这里需要处理多个抽屉叠加的效果
|
||||
AdornerLayer adornerLayer = AdornerLayer.GetAdornerLayer(target);
|
||||
_adorner = _adorner ?? new DrawerAdorner(adornerLayer) { Child = this };
|
||||
this.DrawerClosed = () => adornerLayer.Remove(_adorner);
|
||||
adornerLayer.Add(_adorner);
|
||||
}
|
||||
/// <summary>
|
||||
/// 在参照点【origin】所在的视觉树向上查找Window对象,如果找到则在其可视范围内显示抽屉
|
||||
/// </summary>
|
||||
/// <param name="origin">参照点</param>
|
||||
public void ShowInWindow(FrameworkElement origin, object content = null)
|
||||
{
|
||||
FrameworkElement target = origin;
|
||||
|
||||
while (target != null && !(target is Window)) target = target.Parent as FrameworkElement;
|
||||
|
||||
if (target is Window) this.ShowInTarget(target, content);
|
||||
}
|
||||
/// <summary>
|
||||
/// 在参照点【origin】所在的视觉树内名称为【targetName】名称的UIElement可视范围内显示抽屉
|
||||
/// </summary>
|
||||
/// <param name="origin">参照点</param>
|
||||
/// <param name="targetName">目标UIElement的名称</param>
|
||||
public void ShowInNamedView(FrameworkElement origin, string targetName, object content = null)
|
||||
{
|
||||
FrameworkElement target = origin;
|
||||
|
||||
while (target != null && target.Parent != null && target.Name != targetName) target = target.Parent as FrameworkElement;
|
||||
if (target != null && target.Name != targetName) target = target.FindName(targetName) as FrameworkElement;
|
||||
|
||||
if (target is UIElement && target.Name == targetName) this.ShowInTarget(target, content);
|
||||
}
|
||||
/// <summary>
|
||||
/// 以当前抽屉为模板复制一个新的抽屉,在目标UIElement的可视范围内显示抽屉
|
||||
/// </summary>
|
||||
/// <param name="view">抽屉中承载的内容</param>
|
||||
/// <param name="target">承载抽屉的UI元素</param>
|
||||
/// <param name="title">抽屉的标题</param>
|
||||
/// <param name="callBackSign">请求关闭回调时传入的识别码</param>
|
||||
/// <param name="applyCloseCallBack">抽屉请求关闭时的回调</param>
|
||||
public FutureDrawer ShowNewInTarget(UIElement view, FrameworkElement target, string title, int? callBackSign = null, Func<int?, bool> applyCloseCallBack = null)
|
||||
{
|
||||
FutureDrawer drawer = this.Clone(view, title, callBackSign, applyCloseCallBack);
|
||||
drawer.ShowInTarget(target);
|
||||
return drawer;
|
||||
}
|
||||
/// <summary>
|
||||
/// 以当前抽屉为模板复制一个新的抽屉,以参照原点【origin】为起点沿着视觉树向上查找到的第一个Window对象;在其可视范围内显示抽屉
|
||||
/// </summary>
|
||||
/// <param name="view">抽屉中承载的内容</param>
|
||||
/// <param name="origin">查找的参照点</param>
|
||||
/// <param name="title">抽屉的标题</param>
|
||||
/// <param name="callBackSign">请求关闭回调时传入的识别码</param>
|
||||
/// <param name="applyCloseCallBack">抽屉请求关闭时的回调</param>
|
||||
public void ShowNewInWindow(UIElement view, FrameworkElement origin, string title, int? callBackSign = null, Func<int?, bool> applyCloseCallBack = null)
|
||||
{
|
||||
FutureDrawer drawer = this.Clone(view, title, callBackSign, applyCloseCallBack);
|
||||
drawer?.ShowInWindow(origin);
|
||||
}
|
||||
/// <summary>
|
||||
/// 以当前抽屉为模板复制一个新的抽屉,在参照原点【origin】的视觉树内查找【target】名称的UIElement元素;在其可视范围内显示抽屉
|
||||
/// </summary>
|
||||
/// <param name="view">抽屉中承载的内容</param>
|
||||
/// <param name="origin">查找的参照点</param>
|
||||
/// <param name="targetName">要查找的目标UIElement的名称</param>
|
||||
/// <param name="title">抽屉的标题</param>
|
||||
/// <param name="callBackSign">请求关闭回调时传入的识别码</param>
|
||||
/// <param name="applyCloseCallBack">抽屉请求关闭时的回调</param>
|
||||
public void ShowNewInNamedView(UIElement view, FrameworkElement origin, string targetName, string title, int? callBackSign = null, Func<int?, bool> applyCloseCallBack = null)
|
||||
{
|
||||
FutureDrawer drawer = this.Clone(view, title, callBackSign, applyCloseCallBack);
|
||||
drawer?.ShowInNamedView(origin, targetName);
|
||||
}
|
||||
|
||||
#region 抽屉专用装饰器
|
||||
|
||||
/// <summary>
|
||||
/// 专为抽屉使用的装饰器类
|
||||
/// </summary>
|
||||
private class DrawerAdorner : Adorner
|
||||
{
|
||||
/// <summary>
|
||||
/// Adorner本身没有Child属性,所以这里需要自己加一个
|
||||
/// </summary>
|
||||
private UIElement mChild;
|
||||
public DrawerAdorner(UIElement adornedElement) : base(adornedElement) { }
|
||||
public UIElement Child
|
||||
{
|
||||
get => mChild;
|
||||
set
|
||||
{
|
||||
if (value == null) RemoveVisualChild(mChild);
|
||||
else AddVisualChild(value);
|
||||
|
||||
mChild = value;
|
||||
}
|
||||
}
|
||||
//重写VisualChildrenCount 表示此控件只有一个子控件
|
||||
protected override int VisualChildrenCount => 1;
|
||||
//控件计算大小的时候,我们在装饰层上添加的控件也计算一下大小
|
||||
protected override Size ArrangeOverride(Size finalSize)
|
||||
{
|
||||
mChild?.Arrange(new Rect(finalSize));
|
||||
return finalSize;
|
||||
}
|
||||
//重写GetVisualChild,返回我们添加的控件
|
||||
protected override Visual GetVisualChild(int index)
|
||||
{
|
||||
if (index == 0 && mChild != null) return mChild;
|
||||
return base.GetVisualChild(index);
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
215
Future.Contract/Adorners/LoadingAdorner.cs
Normal file
215
Future.Contract/Adorners/LoadingAdorner.cs
Normal file
@@ -0,0 +1,215 @@
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user