Files
29WxOrder/29WxOrderWpf/Ctrls/OrderCtrls/OrderListCtrl_Property.cs
T
chfei b4615eb41c 订单列表
待采购 增加批量礼物
代发货 增加礼物按钮
2026-08-14 15:59:20 +08:00

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
}