c# winfrom DataGridView 动态UI下载功能(内含GIF图) || 循环可变化的集合 数组 datatable 等
Gif演示
分解步骤
1,使用组件DataGridView
2,使用DataSource来控制表格展示的数据来源(注意:来源需要是DataTable类型)
3,需要用到异步线程。如果是不控制数据源的话,需要使用UI安全线程;(使用Control.Invoke或Control.BeginInvoke方法)
4,DataGridView的列如果设置图片,尽量代码设置
5,DataTable类型也是可以使用LINQ的,参考:AsEnumerable
完整代码
using Newtonsoft.Json; using Sunny.UI.Win32; using Sunny.UI; using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; using WinApp.i18n; using WinApp.Until; using WinApp.ViewModel; using static System.Net.Mime.MediaTypeNames; using Microsoft.EntityFrameworkCore.Metadata.Internal; using System.Security.Cryptography; namespace WinApp.View { public partial class DownloadList : UserControl { /// <summary> /// 开启任务的开关(作用:禁止重复启动任务) /// </summary> private static bool _taskSwitch = true; /// <summary> /// 任务中的小开关(作用:如果被外部干涉,则进行退出执行任务内容) /// </summary> private static bool _taskCondition = true; public DataTable _table; List<DownloadListDto> _mainList; public UILabel _lbNotData; public DownloadList() { InitializeComponent(); var mainTitle = string.Empty; mainTitle = Language.GetLang("downloadTitle1"); mainTitle += "\r" + Language.GetLang("downloadTitle2"); this.uiPanel1.Text = mainTitle; uiDataGridView1.ColumnHeadersVisible = false; uiDataGridView1.RowTemplate.Height = 65; uiDataGridView1.CellBorderStyle = DataGridViewCellBorderStyle.None; _lbNotData = new UILabel(); _lbNotData.Text = "No more data available"; _lbNotData.Cursor = Cursors.Hand; _lbNotData.TextAlign = ContentAlignment.MiddleCenter; _lbNotData.Location = new Point(450, 50); _lbNotData.Width = 200; _lbNotData.Visible = false; this.uiPanel2.Controls.Add(_lbNotData); } private void DownloadList_Load(object sender, EventArgs e) { QueryData(); } public void SetCondition(bool setValue) { _taskCondition = setValue; } public async Task DownloadAllAsync() { if (_taskSwitch) { if (_table.Rows.Count <= 0) { UIMessageDialog.ShowMessageDialog("No more data available", UILocalize.WarningTitle, showCancelButton: false, UIStyle.Orange, false); return; } //已经执行,请勿重复执行; _taskSwitch = false; foreach (DataRow row in _table.Rows) { row["Status"] = "2";//设置为下载中的状态 uiDataGridView1.Refresh(); } while (_table.Rows.Count > 0 && _taskCondition) {//如果列表有数据就一直循环进行下载删除 var firstRow = _table.Rows[0]; if (firstRow == null) {//第一个元素等于NULL return; } for (int j = 0; j <= 100; j++)//模拟进度条 { if (_taskCondition) {//如果没有暂停 await Task.Delay(10); // wait for 100 milliseconds firstRow["DownloadProgress"] = j.ToString(); } else {//暂停 firstRow["Status"] = "1"; } } if (_taskCondition) { // 获取当前行的数据行 var _Id = (int)firstRow["Id"]; // 使用Linq查询匹配的行 var rowsToDelete = _table.AsEnumerable().FirstOrDefault(row => row.Field<int>("Id") == _Id); _table.Rows.Remove(rowsToDelete); } } //foreach (DataRow row in _table.Rows) //{ // row["Status"] = "2"; // for (int j = 0; j <= 100; j++) // { // if (_taskCondition) // { // await Task.Delay(10); // wait for 100 milliseconds // row["DownloadProgress"] = j.ToString(); // } // else // { // row["Status"] = "1"; // } // } // // 获取当前行的数据行 // var _Id = (int)row["Id"]; // // 使用Linq查询匹配的行 // var rowsToDelete = _table.AsEnumerable().FirstOrDefault(row => row.Field<int>("Id") == _Id); // _table.Rows.Remove(rowsToDelete); //} //foreach (var item in _mainList) //{ // item.Status = 2; // uiDataGridView1.Refresh(); // for (int i = 0; i < 100; i++) // { // if (_taskCondition) // { // await Task.Delay(100); // wait for 100 milliseconds // item.DownloadProgress = i.ToString(); // uiDataGridView1.Refresh(); // } // else // { // item.Status = 1; // return; // } // } //} //执行完毕,则可以重新执行 _taskSwitch = true; } else { //因为此次没有执行,下次允许执行; _taskSwitch = true; return; } } public void PauseAll() { SetCondition(false); //获取所有已经开始的数据 var pauseList = _table.AsEnumerable().Where(row => row.Field<int>("Status") == 2); foreach (DataRow item in pauseList) { item["Status"] = "1"; uiDataGridView1.Refresh(); } } public void DeleteAll() { SetCondition(false); // 清除所有行 _table.Clear(); uiDataGridView1.Refresh(); this.uiDataGridView1.Refresh(); } public void QueryData() { LoadingHelper.ShowLoadingScreen(); _mainList = new List<DownloadListDto>(); _mainList.Add(new DownloadListDto() { Id = 1, Title = "A1" + Environment.NewLine + "B1", Status = 1, DownloadProgress = "0" }); _mainList.Add(new DownloadListDto() { Id = 2, Title = "A2" + Environment.NewLine + "B2", Status = 1, DownloadProgress = "0" }); _mainList.Add(new DownloadListDto() { Id = 3, Title = "A3" + Environment.NewLine + "B3", Status = 1, DownloadProgress = "0" }); _mainList.Add(new DownloadListDto() { Id = 4, Title = "A4" + Environment.NewLine + "B4", Status = 1, DownloadProgress = "0" }); _mainList.Add(new DownloadListDto() { Id = 5, Title = "A5" + Environment.NewLine + "B5", Status = 1, DownloadProgress = "0" }); _table = _mainList.ToDataTable(); this.uiDataGridView1.DataSource = _table; LoadingHelper.CloseForm(); uiDataGridView1.ClearSelection(); } private void uiDataGridView1_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e) { DataGridViewRow row = uiDataGridView1.Rows[e.RowIndex]; if (uiDataGridView1.Columns[e.ColumnIndex].Name == "clTitle") { if (row.Cells["clStatus"].Value is int) { var intStatus = (int)row.Cells["clStatus"].Value; if (intStatus == 1) { row.Cells["clOpDown"].Value = FileHelper.loadImageFromLocalPath(@"FileFolder/Icon/downLoad.png"); row.Cells["clOpDelete"].Value = FileHelper.loadImageFromLocalPath(@"FileFolder/Icon/delete1.png"); } else if (intStatus == 2) { row.Cells["clOpDown"].Value = FileHelper.loadImageFromLocalPath(@"FileFolder/Icon/pause.png"); row.Cells["clOpDelete"].Value = FileHelper.loadImageFromLocalPath(@"FileFolder/Icon/delete1.png"); //row.Cells["clOpDelete"].Value = null; } else { // 创建一个1x1像素的透明图像 Bitmap transparentImage = new Bitmap(1, 1); transparentImage.SetPixel(0, 0, Color.Transparent); row.Cells["clOpDown"].Value = transparentImage; row.Cells["clOpDelete"].Value = transparentImage; } } } } private void uiDataGridView1_CellClick(object sender, DataGridViewCellEventArgs e) { //uiDataGridView1.ClearSelection(); } private async void uiDataGridView1_CellContentClick(object sender, DataGridViewCellEventArgs e) { if (uiDataGridView1.Columns[e.ColumnIndex] is DataGridViewImageColumn && e.RowIndex >= 0) { // 获取当前行的数据行 var currentRow = uiDataGridView1.Rows[e.RowIndex]; var _Id = (int)currentRow.Cells["clId"].Value; if (uiDataGridView1.Columns[e.ColumnIndex].Name == "clOpDown") { //var currentData = _mainList.Find(x => x.Id == _Id); var currentData = _table.AsEnumerable().FirstOrDefault(x => x.Field<int>("Id") == _Id); if (currentData != null) { if (currentData["Status"].ToString() == "1") {//1代表 未下载 currentData["Status"] = "2";//修改图标 uiDataGridView1.Refresh(); } else {//2代表 正在下载 _taskCondition = false;//终止执行任务 currentData["Status"] = "1";//修改图标 uiDataGridView1.Refresh(); } //currentData.Status = 1; //_taskCondition = false; //uiDataGridView1.Refresh(); } } if (uiDataGridView1.Columns[e.ColumnIndex].Name == "clOpDelete") { // 使用Linq查询匹配的行 var rowsToDelete = _table.AsEnumerable().FirstOrDefault(row => row.Field<int>("Id") == _Id); _table.Rows.Remove(rowsToDelete); } } } public void DeleteMainData(int Id) { var currentData = _mainList.Find(x => x.Id == Id); if (currentData != null) { _mainList.Remove(currentData); uiDataGridView1.DataSource = _mainList; uiDataGridView1.Refresh(); } } private void uiDataGridView1_DataBindingComplete(object sender, DataGridViewBindingCompleteEventArgs e) { uiDataGridView1.Visible = true; _lbNotData.Visible = false; DataGridView dataGridView = (DataGridView)sender; if (dataGridView.Rows.Count == 0) { uiDataGridView1.Dock = DockStyle.None; uiDataGridView1.Visible = false; _lbNotData.Visible = true; } } private void uiDataGridView1_DataError(object sender, DataGridViewDataErrorEventArgs e) { // 取消默认的错误处理行为 e.ThrowException = false; // 获取出错的单元格 DataGridViewCell errorCell = uiDataGridView1.Rows[e.RowIndex].Cells[e.ColumnIndex]; // 获取出错的数据 object errorValue = uiDataGridView1.Rows[e.RowIndex].Cells[e.ColumnIndex].Value; // 自定义错误处理逻辑 MessageBox.Show("数据错误:" + e.Exception.Message); // 可以将出错的单元格的值重置为默认值 errorCell.Value = errorCell.DefaultNewRowValue; } } }
结语
上面完整代码是.cs的代码。大家拷贝本地使用的时候需要在UI界面进行拖拉组件。本例子用的是winform SunnyUI 的框架 。框架文档在这里:文档预览 - Gitee.com
从前慢,车马慢。
一生只爱一个人。