using BPASmartClient.CustomResource.UserControls.Enum;
using BPASmartClient.CustomResource.UserControls.Model;
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.Controls.Primitives;
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 BPASmartClient.CustomResource.UserControls
{
///
/// Toast.xaml 的交互逻辑
///
public partial class Toast : UserControl
{
private Window owner = null;
private Popup popup = null;
private DispatcherTimer timer = null;
private Toast()
{
InitializeComponent();
this.DataContext = this;
}
private Toast(Window owner, string message, ToastOptions options = null)
{
Message = message;
InitializeComponent();
if (options != null)
{
if (options.ToastWidth != 0) ToastWidth = options.ToastWidth;
if (options.ToastHeight != 0) ToastHeight = options.ToastHeight;
if (options.TextWidth != 0) TextWidth = options.TextWidth;
Icon = options.Icon;
Location = options.Location;
Time = options.Time;
Closed += options.Closed;
Click += options.Click;
Background = options.Background;
Foreground = options.Foreground;
FontStyle = options.FontStyle;
FontStretch = options.FontStretch;
FontSize = options.FontSize;
FontFamily = options.FontFamily;
FontWeight = options.FontWeight;
IconSize = options.IconSize;
BorderBrush = options.BorderBrush;
BorderThickness = options.BorderThickness;
HorizontalContentAlignment = options.HorizontalContentAlignment;
VerticalContentAlignment = options.VerticalContentAlignment;
CornerRadius = options.CornerRadius;
ToastMargin = options.ToastMargin;
IconForeground = options.IconForeground;
}
this.DataContext = this;
if (owner == null)
{
this.owner = Application.Current.MainWindow;
}
else
{
this.owner = owner;
}
this.owner.Closed += Owner_Closed;
}
private void Owner_Closed(object sender, EventArgs e)
{
this.Close();
}
public static void Show(string msg, ToastOptions options = null)
{
var toast = new Toast(null, msg, options);
int time = toast.Time;
ShowToast(toast, time);
}
public static void Show(Window owner, string msg, ToastOptions options = null)
{
var toast = new Toast(owner, msg, options);
int time = toast.Time;
ShowToast(toast, time);
}
private static void ShowToast(Toast toast, int time)
{
toast.popup = null;
Application.Current.Dispatcher.Invoke(new Action(() =>
{
toast.popup = new Popup
{
PopupAnimation = PopupAnimation.Fade,
AllowsTransparency = true,
StaysOpen = true,
Placement = PlacementMode.Left,
IsOpen = false,
Child = toast,
MinWidth = toast.MinWidth,
MaxWidth = toast.MaxWidth,
MinHeight = toast.MinHeight,
MaxHeight = toast.MaxHeight,
};
if (toast.ToastWidth != 0)
{
toast.popup.Width = toast.ToastWidth;
}
if (toast.ToastHeight != 0)
{
toast.popup.Height = toast.ToastHeight;
}
toast.popup.PlacementTarget = GetPopupPlacementTarget(toast); //为 null 则 Popup 定位相对于屏幕的左上角;
toast.owner.LocationChanged += toast.UpdatePosition;
toast.owner.SizeChanged += toast.UpdatePosition;
toast.popup.Closed += Popup_Closed;
//SetPopupOffset(toast.popup, toast);
//toast.UpdatePosition(toast, null);
toast.popup.IsOpen = true; //先显示出来以确定宽高;
SetPopupOffset(toast.popup, toast);
//toast.UpdatePosition(toast, null);
toast.popup.IsOpen = false; //先关闭再打开来刷新定位;
toast.popup.IsOpen = true;
}));
toast.timer = new DispatcherTimer();
toast.timer.Tick += (sender, e) =>
{
toast.popup.IsOpen = false;
toast.owner.LocationChanged -= toast.UpdatePosition;
toast.owner.SizeChanged -= toast.UpdatePosition;
};
toast.timer.Interval = new TimeSpan(0, 0, 0, 0, time);
toast.timer.Start();
}
private void UpdatePosition(object sender, EventArgs e)
{
var up = typeof(Popup).GetMethod("UpdatePosition", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
if (up == null || popup == null)
{
return;
}
SetPopupOffset(popup, this);
up.Invoke(popup, null);
}
private static void Popup_Closed(object sender, EventArgs e)
{
Popup popup = sender as Popup;
if (popup == null)
{
return;
}
Toast toast = popup.Child as Toast;
if (toast == null)
{
return;
}
toast.RaiseClosed(e);
}
private void UserControl_MouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
if (e.ClickCount == 1)
{
RaiseClick(e);
}
}
///
/// 获取定位目标
///
/// Toast 对象
/// 容器或null
private static UIElement GetPopupPlacementTarget(Toast toast)
{
switch (toast.Location)
{
case ToastLocation.ScreenCenter:
case ToastLocation.ScreenLeft:
case ToastLocation.ScreenRight:
case ToastLocation.ScreenTopLeft:
case ToastLocation.ScreenTopCenter:
case ToastLocation.ScreenTopRight:
case ToastLocation.ScreenBottomLeft:
case ToastLocation.ScreenBottomCenter:
case ToastLocation.ScreenBottomRight:
return null;
}
return toast.owner;
}
private static void SetPopupOffset(Popup popup, Toast toast)
{
double winTitleHeight = SystemParameters.CaptionHeight; //标题高度为22;
double owner_width = toast.owner.ActualWidth;
double owner_height = toast.owner.ActualHeight - winTitleHeight;
if (popup.PlacementTarget == null)
{
owner_width = SystemParameters.WorkArea.Size.Width;
owner_height = SystemParameters.WorkArea.Size.Height;
}
double popupWidth = (popup.Child as FrameworkElement)?.ActualWidth ?? 0; //Popup 宽高为其 Child 的宽高;
double popupHeight = (popup.Child as FrameworkElement)?.ActualHeight ?? 0;
double x = SystemParameters.WorkArea.X;
double y = SystemParameters.WorkArea.Y;
Thickness margin = toast.ToastMargin;
/*[dlgcy] 38 和 16 两个数字的猜测:
* PlacementTarget 为 Window 时,当 Placement 为 Bottom 时,Popup 上边缘与 Window 的下边缘的距离为 38;
* 当 Placement 为 Right 时,Popup 左边缘与 Window 的右边缘的距离为 16。
*/
double bottomDistance = 38;
double rightDistance = 16;
//上面创建时 Popup 的 Placement 为 PlacementMode.Left;
switch (toast.Location)
{
case ToastLocation.OwnerLeft: //容器左中间
popup.HorizontalOffset = popupWidth + margin.Left;
popup.VerticalOffset = (owner_height - popupHeight - winTitleHeight) / 2;
break;
case ToastLocation.ScreenLeft: //屏幕左中间
popup.HorizontalOffset = popupWidth + x + margin.Left;
popup.VerticalOffset = (owner_height - popupHeight) / 2 + y;
break;
case ToastLocation.OwnerRight: //容器右中间
popup.HorizontalOffset = owner_width - rightDistance - margin.Right;
popup.VerticalOffset = (owner_height - popupHeight - winTitleHeight) / 2;
break;
case ToastLocation.ScreenRight: //屏幕右中间
popup.HorizontalOffset = owner_width + x - margin.Right;
popup.VerticalOffset = (owner_height - popupHeight) / 2 + y;
break;
case ToastLocation.OwnerTopLeft: //容器左上角
popup.HorizontalOffset = popupWidth + margin.Left;
popup.VerticalOffset = margin.Top;
break;
case ToastLocation.ScreenTopLeft: //屏幕左上角
popup.HorizontalOffset = popupWidth + x + margin.Left;
popup.VerticalOffset = margin.Top;
break;
case ToastLocation.OwnerTopCenter: //容器上中间
popup.HorizontalOffset = popupWidth + (owner_width - popupWidth - rightDistance) / 2;
popup.VerticalOffset = margin.Top;
break;
case ToastLocation.ScreenTopCenter: //屏幕上中间
popup.HorizontalOffset = popupWidth + (owner_width - popupWidth) / 2 + x;
popup.VerticalOffset = y + margin.Top;
break;
case ToastLocation.OwnerTopRight: //容器右上角
popup.HorizontalOffset = owner_width - rightDistance - margin.Right;
popup.VerticalOffset = margin.Top;
break;
case ToastLocation.ScreenTopRight: //屏幕右上角
popup.HorizontalOffset = owner_width + x - margin.Right;
popup.VerticalOffset = y + margin.Top;
break;
case ToastLocation.OwnerBottomLeft: //容器左下角
//popup.HorizontalOffset = popupWidth;
//popup.VerticalOffset = owner_height - popupHeight - winTitleHeight;
popup.Placement = PlacementMode.Bottom;
popup.HorizontalOffset = margin.Left;
popup.VerticalOffset = -(bottomDistance + popupHeight + margin.Bottom);
break;
case ToastLocation.ScreenBottomLeft: //屏幕左下角
popup.HorizontalOffset = popupWidth + x + margin.Left;
popup.VerticalOffset = owner_height - popupHeight + y - margin.Bottom;
break;
case ToastLocation.OwnerBottomCenter: //容器下中间
//popup.HorizontalOffset = popupWidth + (owner_width - popupWidth - rightDistance) / 2;
//popup.VerticalOffset = owner_height - popupHeight - winTitleHeight;
popup.Placement = PlacementMode.Bottom;
popup.HorizontalOffset = (owner_width - popupWidth - rightDistance) / 2;
popup.VerticalOffset = -(bottomDistance + popupHeight + margin.Bottom);
break;
case ToastLocation.ScreenBottomCenter: //屏幕下中间
popup.HorizontalOffset = popupWidth + (owner_width - popupWidth) / 2 + x;
popup.VerticalOffset = owner_height - popupHeight + y - margin.Bottom;
break;
case ToastLocation.OwnerBottomRight: //容器右下角
//popup.HorizontalOffset = popupWidth + (owner_width - popupWidth - rightDistance);
//popup.VerticalOffset = owner_height - popupHeight - winTitleHeight;
popup.Placement = PlacementMode.Bottom;
popup.HorizontalOffset = owner_width - popupWidth - rightDistance - margin.Right;
popup.VerticalOffset = -(bottomDistance + popupHeight + margin.Bottom);
break;
case ToastLocation.ScreenBottomRight: //屏幕右下角
popup.HorizontalOffset = owner_width + x - margin.Right;
popup.VerticalOffset = owner_height - popupHeight + y - margin.Bottom;
break;
case ToastLocation.ScreenCenter: //屏幕正中间
popup.HorizontalOffset = popupWidth + (owner_width - popupWidth) / 2 + x;
popup.VerticalOffset = (owner_height - popupHeight) / 2 + y;
break;
case ToastLocation.OwnerCenter: //容器正中间
case ToastLocation.Default:
//popup.HorizontalOffset = popupWidth + (owner_width - popupWidth - rightDistance) / 2;
//popup.VerticalOffset = (owner_height - popupHeight - winTitleHeight) / 2;
popup.Placement = PlacementMode.Center;
popup.HorizontalOffset = -rightDistance / 2;
popup.VerticalOffset = -bottomDistance / 2;
break;
}
}
public void Close()
{
if (timer != null)
{
timer.Stop();
timer = null;
}
popup.IsOpen = false;
owner.LocationChanged -= UpdatePosition;
owner.SizeChanged -= UpdatePosition;
}
private event EventHandler Closed;
private void RaiseClosed(EventArgs e)
{
Closed?.Invoke(this, e);
}
private event EventHandler Click;
private void RaiseClick(EventArgs e)
{
Click?.Invoke(this, e);
}
#region 依赖属性
private string Message
{
get { return (string)GetValue(MessageProperty); }
set { SetValue(MessageProperty, value); }
}
private static readonly DependencyProperty MessageProperty =
DependencyProperty.Register("Message", typeof(string), typeof(Toast), new PropertyMetadata(string.Empty));
private CornerRadius CornerRadius
{
get { return (CornerRadius)GetValue(CornerRadiusProperty); }
set { SetValue(CornerRadiusProperty, value); }
}
private static readonly DependencyProperty CornerRadiusProperty =
DependencyProperty.Register("CornerRadius", typeof(CornerRadius), typeof(Toast), new PropertyMetadata(new CornerRadius(5)));
private double IconSize
{
get { return (double)GetValue(IconSizeProperty); }
set { SetValue(IconSizeProperty, value); }
}
private static readonly DependencyProperty IconSizeProperty =
DependencyProperty.Register("IconSize", typeof(double), typeof(Toast), new PropertyMetadata(26.0));
private new Brush BorderBrush
{
get { return (Brush)GetValue(BorderBrushProperty); }
set { SetValue(BorderBrushProperty, value); }
}
private static new readonly DependencyProperty BorderBrushProperty =
DependencyProperty.Register("BorderBrush", typeof(Brush), typeof(Toast), new PropertyMetadata((Brush)new BrushConverter().ConvertFromString("#FFFFFF")));
private new Thickness BorderThickness
{
get { return (Thickness)GetValue(BorderThicknessProperty); }
set { SetValue(BorderThicknessProperty, value); }
}
private static new readonly DependencyProperty BorderThicknessProperty =
DependencyProperty.Register("BorderThickness", typeof(Thickness), typeof(Toast), new PropertyMetadata(new Thickness(0)));
private new Brush Background
{
get { return (Brush)GetValue(BackgroundProperty); }
set { SetValue(BackgroundProperty, value); }
}
private static new readonly DependencyProperty BackgroundProperty =
DependencyProperty.Register("Background", typeof(Brush), typeof(Toast), new PropertyMetadata((Brush)new BrushConverter().ConvertFromString("#2E2929")));
private new HorizontalAlignment HorizontalContentAlignment
{
get { return (HorizontalAlignment)GetValue(HorizontalContentAlignmentProperty); }
set { SetValue(HorizontalContentAlignmentProperty, value); }
}
private static new readonly DependencyProperty HorizontalContentAlignmentProperty =
DependencyProperty.Register("HorizontalContentAlignment", typeof(HorizontalAlignment), typeof(Toast), new PropertyMetadata(HorizontalAlignment.Left));
private new VerticalAlignment VerticalContentAlignment
{
get { return (VerticalAlignment)GetValue(VerticalContentAlignmentProperty); }
set { SetValue(VerticalContentAlignmentProperty, value); }
}
private static new readonly DependencyProperty VerticalContentAlignmentProperty =
DependencyProperty.Register("VerticalContentAlignment", typeof(VerticalAlignment), typeof(Toast), new PropertyMetadata(VerticalAlignment.Center));
private double ToastWidth
{
get { return (double)GetValue(ToastWidthProperty); }
set { SetValue(ToastWidthProperty, value); }
}
private static readonly DependencyProperty ToastWidthProperty =
DependencyProperty.Register("ToastWidth", typeof(double), typeof(Toast), new PropertyMetadata(0.0));
private double ToastHeight
{
get { return (double)GetValue(ToastHeightProperty); }
set { SetValue(ToastHeightProperty, value); }
}
private static readonly DependencyProperty ToastHeightProperty =
DependencyProperty.Register("ToastHeight", typeof(double), typeof(Toast), new PropertyMetadata(0.0));
private ToastIcons Icon
{
get { return (ToastIcons)GetValue(IconProperty); }
set { SetValue(IconProperty, value); }
}
private static readonly DependencyProperty IconProperty =
DependencyProperty.Register("Icon", typeof(ToastIcons), typeof(Toast), new PropertyMetadata(ToastIcons.None));
private int Time
{
get { return (int)GetValue(TimeProperty); }
set { SetValue(TimeProperty, value); }
}
private static readonly DependencyProperty TimeProperty =
DependencyProperty.Register("Time", typeof(int), typeof(Toast), new PropertyMetadata(2000));
private ToastLocation Location
{
get { return (ToastLocation)GetValue(LocationProperty); }
set { SetValue(LocationProperty, value); }
}
private static readonly DependencyProperty LocationProperty =
DependencyProperty.Register("Location", typeof(ToastLocation), typeof(Toast), new PropertyMetadata(ToastLocation.Default));
public double TextWidth
{
get { return (double)GetValue(TextWidthProperty); }
set { SetValue(TextWidthProperty, value); }
}
public static readonly DependencyProperty TextWidthProperty =
DependencyProperty.Register("TextWidth", typeof(double), typeof(Toast), new PropertyMetadata(double.NaN));
public Thickness ToastMargin
{
get { return (Thickness)GetValue(ToastMarginProperty); }
set { SetValue(ToastMarginProperty, value); }
}
public static readonly DependencyProperty ToastMarginProperty =
DependencyProperty.Register("ToastMargin", typeof(Thickness), typeof(Toast), new PropertyMetadata(new Thickness(0)));
private Brush IconForeground
{
get { return (Brush)GetValue(IconForegroundProperty); }
set { SetValue(IconForegroundProperty, value); }
}
private static readonly DependencyProperty IconForegroundProperty =
DependencyProperty.Register("IconForeground", typeof(Brush), typeof(Toast), new PropertyMetadata((Brush)new BrushConverter().ConvertFromString("#00D91A")));
#endregion
}
}