182 lines
5.4 KiB
C#
182 lines
5.4 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.ComponentModel;
|
|
using System.Linq;
|
|
using System.Runtime.CompilerServices;
|
|
using System.Text;
|
|
using System.Threading.Tasks;
|
|
|
|
namespace _29WxOrderWpf.Ctrls.OrderCtrls;
|
|
|
|
public partial class OrderListCtrl : INotifyPropertyChanged
|
|
{
|
|
#region NotifayProperty
|
|
/// <summary>
|
|
/// Occurs when a property value changes.
|
|
/// </summary>
|
|
public event PropertyChangedEventHandler PropertyChanged;
|
|
|
|
/// <summary>
|
|
/// Checks if a property already matches a desired value. Sets the property and
|
|
/// notifies listeners only when necessary.
|
|
/// </summary>
|
|
/// <typeparam name="T">Type of the property.</typeparam>
|
|
/// <param name="storage">Reference to a property with both getter and setter.</param>
|
|
/// <param name="value">Desired value for the property.</param>
|
|
/// <param name="propertyName">Name of the property used to notify listeners. This
|
|
/// value is optional and can be provided automatically when invoked from compilers that
|
|
/// support CallerMemberName.</param>
|
|
/// <returns>True if the value was changed, false if the existing value matched the
|
|
/// desired value.</returns>
|
|
protected virtual bool SetProperty<T>(ref T storage, T value, [CallerMemberName] string propertyName = null)
|
|
{
|
|
if (EqualityComparer<T>.Default.Equals(storage, value)) return false;
|
|
|
|
storage = value;
|
|
RaisePropertyChanged(propertyName);
|
|
|
|
return true;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Checks if a property already matches a desired value. Sets the property and
|
|
/// notifies listeners only when necessary.
|
|
/// </summary>
|
|
/// <typeparam name="T">Type of the property.</typeparam>
|
|
/// <param name="storage">Reference to a property with both getter and setter.</param>
|
|
/// <param name="value">Desired value for the property.</param>
|
|
/// <param name="propertyName">Name of the property used to notify listeners. This
|
|
/// value is optional and can be provided automatically when invoked from compilers that
|
|
/// support CallerMemberName.</param>
|
|
/// <param name="onChanged">Action that is called after the property value has been changed.</param>
|
|
/// <returns>True if the value was changed, false if the existing value matched the
|
|
/// desired value.</returns>
|
|
protected virtual bool SetProperty<T>(ref T storage, T value, Action onChanged, [CallerMemberName] string propertyName = null)
|
|
{
|
|
if (EqualityComparer<T>.Default.Equals(storage, value)) return false;
|
|
|
|
storage = value;
|
|
onChanged?.Invoke();
|
|
RaisePropertyChanged(propertyName);
|
|
|
|
return true;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Raises this object's PropertyChanged event.
|
|
/// </summary>
|
|
/// <param name="propertyName">Name of the property used to notify listeners. This
|
|
/// value is optional and can be provided automatically when invoked from compilers
|
|
/// that support <see cref="CallerMemberNameAttribute"/>.</param>
|
|
protected void RaisePropertyChanged([CallerMemberName] string propertyName = null)
|
|
{
|
|
OnPropertyChanged(new PropertyChangedEventArgs(propertyName));
|
|
}
|
|
|
|
/// <summary>
|
|
/// Raises this object's PropertyChanged event.
|
|
/// </summary>
|
|
/// <param name="args">The PropertyChangedEventArgs</param>
|
|
protected virtual void OnPropertyChanged(PropertyChangedEventArgs args)
|
|
{
|
|
PropertyChanged?.Invoke(this, args);
|
|
}
|
|
#endregion
|
|
|
|
|
|
private string _bottomMsg = "";
|
|
public string BottomMsg
|
|
{
|
|
get => _bottomMsg;
|
|
set => SetProperty(ref _bottomMsg, value);
|
|
}
|
|
|
|
private double _progressValue;
|
|
public double ProgressValue
|
|
{
|
|
get => _progressValue;
|
|
set => SetProperty(ref _progressValue, value);
|
|
}
|
|
|
|
private double _progressMaximum = 100;
|
|
public double ProgressMaximum
|
|
{
|
|
get => _progressMaximum;
|
|
set => SetProperty(ref _progressMaximum, value);
|
|
}
|
|
public void SetProgress(int value, int maxValue)
|
|
{
|
|
StopUnknownTotalProgressTimer();
|
|
ProgressValue = value;
|
|
ProgressMaximum = maxValue;
|
|
}
|
|
|
|
#region 未知总数百分比模拟进度
|
|
private System.Threading.Timer _unknownTotalProgressTimer;
|
|
private DateTime _unknownTotalProgressStartTime;
|
|
|
|
/// <summary>
|
|
/// 开始未知总数的百分比模拟进度:80% 之前走得快,越到最后走得越慢,
|
|
/// 理论上永远走不到 95% 以上,直到调用 <see cref="CompleteProgress"/> 才会变成 100%。
|
|
/// </summary>
|
|
public void StartProgress()
|
|
{
|
|
StopUnknownTotalProgressTimer();
|
|
ProgressMaximum = 100;
|
|
ProgressValue = 0;
|
|
_unknownTotalProgressStartTime = DateTime.Now;
|
|
_unknownTotalProgressTimer = new System.Threading.Timer(_ => UpdateUnknownTotalProgress(), null, 0, 200);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 结束进度:停止模拟,进度条立即变为 100%。
|
|
/// </summary>
|
|
public void CompleteProgress()
|
|
{
|
|
StopUnknownTotalProgressTimer();
|
|
ProgressMaximum = 100;
|
|
ProgressValue = 100;
|
|
}
|
|
|
|
private void UpdateUnknownTotalProgress()
|
|
{
|
|
try
|
|
{
|
|
Dispatcher.BeginInvoke(new Action(() =>
|
|
{
|
|
var elapsed = (DateTime.Now - _unknownTotalProgressStartTime).TotalSeconds;
|
|
double progress;
|
|
if (elapsed <= 10)
|
|
{
|
|
// 前 10 秒内快速推进到 80%
|
|
progress = Math.Max(0, Math.Min(80, elapsed * 8));
|
|
}
|
|
else
|
|
{
|
|
// 超过 80% 后指数衰减越来越慢,渐近线为 95%,理论上永远走不到 95% 以上
|
|
progress = 95.0 - 15.0 * Math.Exp(-(elapsed - 10.0) / 20.0);
|
|
}
|
|
if (progress > 95) progress = 95;
|
|
ProgressValue = progress;
|
|
}));
|
|
}
|
|
catch
|
|
{
|
|
}
|
|
}
|
|
|
|
private void StopUnknownTotalProgressTimer()
|
|
{
|
|
if (_unknownTotalProgressTimer == null) return;
|
|
try
|
|
{
|
|
_unknownTotalProgressTimer.Dispose();
|
|
}
|
|
catch
|
|
{
|
|
}
|
|
_unknownTotalProgressTimer = null;
|
|
}
|
|
#endregion
|
|
}
|