using PTMedicalInsurance.Variables; using System; using System.Collections.Generic; using System.ComponentModel; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; namespace PTMedicalInsurance.Common { public class ProgressDialog : Form { private ProgressBar progressBar1; private Label labelStatus; private Button cancelButton; BackgroundWorker _backgroundWorker; private int maximum; private ProgressBarStyle _pbStyle = ProgressBarStyle.Marquee; private string _header = "正在查询..."; private int _marqueeAnimationSpeed = 50; public string HeaderText { get { return _header; } set { this.Text =_header = value; } } public ProgressBarStyle PBStyle { get { return _pbStyle; } set { progressBar1.Style =_pbStyle = value; } } public int MQSpeed { get { return _marqueeAnimationSpeed; } set { progressBar1.MarqueeAnimationSpeed =_marqueeAnimationSpeed = value; } } public ProgressDialog() { Init(); } public ProgressDialog(BackgroundWorker backgroundWorker) { Init(); _backgroundWorker = backgroundWorker; } private void Init() { Application.EnableVisualStyles(); this.Text = _header; this.StartPosition = FormStartPosition.CenterParent; this.FormBorderStyle = FormBorderStyle.FixedDialog; this.MaximizeBox = false; this.MinimizeBox = false; this.ShowInTaskbar = false; this.TopMost = true; // 确保进度条始终在最前面 this.CenterToScreen(); progressBar1 = new ProgressBar { Location = new System.Drawing.Point(12, 12), Size = new System.Drawing.Size(260, 23) }; //progressBar1.Style = ProgressBarStyle.Continuous; progressBar1.Style = _pbStyle; progressBar1.MarqueeAnimationSpeed = _marqueeAnimationSpeed; Controls.Add(progressBar1); labelStatus = new Label { Location = new System.Drawing.Point(12, 41), Size = new System.Drawing.Size(260, 23) }; Controls.Add(labelStatus); //// 初始化取消按钮 //cancelButton = new Button //{ // Text = "取消", // Location = new System.Drawing.Point(197, 41), // 设置适当的位置 // Size = new System.Drawing.Size(75, 23) // 设置按钮大小 //}; //cancelButton.Click += CancelButton_Click; // 添加点击事件处理程序 //Controls.Add(cancelButton); // 初始化取消按钮 cancelButton = new Button { Text = "取消", Location = new System.Drawing.Point(197, 60), // 修改Y坐标以避免与labelStatus重叠 Size = new System.Drawing.Size(75, 23) // 设置按钮大小 }; cancelButton.Click += CancelButton_Click; // 添加点击事件处理程序 Controls.Add(cancelButton); // 设置默认样式 SetStyle(ControlStyles.ResizeRedraw, true); ClientSize = new System.Drawing.Size(284, 100); } // 允许外部设置进度条的值 public int ProgressValue { set { if (InvokeRequired) Invoke(new Action(() => progressBar1.Value = value)); else progressBar1.Value = value; } } public void UpdateProgress(int progress) { //if (progressBar1.InvokeRequired) //{ // progressBar1.Invoke(new Action(UpdateProgress), progress); //} //else //{ // progressBar1.Value = progress; // //这个有点糊涂了,这个进度条显示总是少一个 // labelStatus.Text = $"已完成 {progress}/{maximum}"; //} this.Invoke((MethodInvoker)delegate { progressBar1.Value = progress; //这个有点糊涂了,这个进度条显示总是少一个 labelStatus.Text = $"已完成 {progress}/{maximum}"; ///在Windows Forms应用程序中,控件的更新通常是由操作系统消息循环处理的。当你修改一个控件的属性(如 Text 或 Value), ///这些更改并不会立即反映在界面上,而是会被放入队列等待下一个合适的时机进行绘制。这是因为直接更新控件属性并不会强制执行重绘操作, ///系统可能会批量处理多个更新以提高效率。 ///使用 Refresh() 方法 调用控件的 Refresh() 方法会强制该控件立即重绘自身。这包括清除控件并重新绘制其所有内容 if (progress == maximum) { progressBar1.Refresh(); labelStatus.Refresh(); } }); } public void SetProgress(int max) { maximum = max; progressBar1.Maximum = maximum; } // 允许外部设置状态文本 public string StatusText { set { if (InvokeRequired) Invoke(new Action(() => labelStatus.Text = value)); else labelStatus.Text = value; } } //异步展示 public async void ShowAsync() { await Task.Run(() => progressBar1.Show()); } private void CancelButton_Click(object sender, EventArgs e) { // 这里可以放置取消操作的逻辑 // 比如通知BackgroundWorker取消工作 if (_backgroundWorker != null && _backgroundWorker.WorkerSupportsCancellation) { _backgroundWorker.CancelAsync(); } this.Close(); // 关闭对话框 } } public class DataLoader : IDisposable { private BackgroundWorker _backgroundWorker = new BackgroundWorker(); public delegate int MyFunc(out T1 err,ProgressCallback progressCallback); private MyFunc _delegateFunc; private ProgressDialog progressDialog ; private Form mainForm; // 定义进度回调委托 public delegate void ProgressCallback(int progress); public DataLoader(MyFunc delegateFunc, Form frm) { mainForm = frm; _delegateFunc = delegateFunc ?? throw new ArgumentNullException(nameof(delegateFunc)); // 配置 BackgroundWorker _backgroundWorker.WorkerReportsProgress = true; _backgroundWorker.WorkerSupportsCancellation = true; _backgroundWorker.DoWork += BackgroundWorker_DoWork; _backgroundWorker.RunWorkerCompleted += BackgroundWorker_RunWorkerCompleted; _backgroundWorker.ProgressChanged += BackgroundWorker_ProgressChanged; progressDialog = new ProgressDialog(_backgroundWorker); } public DataLoader(Form frm) { mainForm = frm; // 配置 BackgroundWorker _backgroundWorker.WorkerReportsProgress = true; _backgroundWorker.WorkerSupportsCancellation = true; _backgroundWorker.DoWork += BackgroundWorker_DoWork; _backgroundWorker.RunWorkerCompleted += BackgroundWorker_RunWorkerCompleted; _backgroundWorker.ProgressChanged += BackgroundWorker_ProgressChanged; progressDialog = new ProgressDialog(_backgroundWorker); } public void SetDelagate(MyFunc delegateFunc) { _delegateFunc = delegateFunc ?? throw new ArgumentNullException(nameof(delegateFunc)); } public void SetProgressBar(ProgressBarStyle pbStyle,string headerText,int mqSpeed) { progressDialog.PBStyle = pbStyle; progressDialog.HeaderText = headerText; progressDialog.MQSpeed = mqSpeed; } public void StartQueryExportData(int total, Action onCompleted) { if (mainForm == null) { progressDialog.Show(); } else { progressDialog.Show(mainForm); } if (_backgroundWorker.IsBusy) return; this._onCompleted = onCompleted; _backgroundWorker.RunWorkerAsync(total); } private Action _onCompleted; private void BackgroundWorker_DoWork(object sender, DoWorkEventArgs e) { // 调用传入的方法 string errMsg = ""; int result = -1; int total = (int)e.Argument; // 获取传入的总项目数 if (total > 0) { progressDialog.SetProgress(total); //注意,如果_queryExportDataAction 事件里需要更新UI 必须使用 Control.Invoke 或 Control.BeginInvoke。否则会导致程序卡死 ///类似这样:this.Invoke((MethodInvoker)delegate {labelProgress.Text = $"Progress: {progress}%"; }); result = _delegateFunc(out errMsg, (progress) => { if (!_backgroundWorker.CancellationPending) { _backgroundWorker.ReportProgress(progress); } else { // 如果用户请求了取消,则跳出循环或采取其他措施 // 这个异常处理查询下 throw new OperationCanceledException(); } }); } else { result = _delegateFunc(out errMsg, (progress) => { }); } e.Result = Tuple.Create(result, errMsg); } private void BackgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) { if (!_backgroundWorker.CancellationPending) { System.Threading.Thread.Sleep(1000); } progressDialog.Close(); if (e.Error != null) { // 处理错误 MessageBox.Show($"An error occurred: {e.Error.Message}"); } else if (e.Cancelled) { // 处理取消的情况 MessageBox.Show("Operation was cancelled."); } else { var resultTuple = (Tuple)e.Result; int result = resultTuple.Item1; string errMsg = resultTuple.Item2; // 调用回调函数,传递结果和错误信息 _onCompleted?.Invoke(result, errMsg); } Dispose(); } private void BackgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e) { progressDialog.UpdateProgress(e.ProgressPercentage ); } public void Dispose() { _backgroundWorker.Dispose(); progressDialog.Dispose(); } } }