前言:SmartProject 项目是C#桌面程序的精简版,很多属性和事件可能都没有设置进SDK中。在最近的PDA程序中,我没用使用进度条。为了防止用户乱点,最开始想使用windows提供的进度条,但是觉得又不适合,所以就试图用图片切换的方式来实现。
原理:开启线程切换图片实现显示(子线程不影响主线程而继续往下执行)。
1、进度界面设计效果
2、界面切换效果
点击质检按钮后跳转(during the new thread running the UI will be changed):
等待业务线程(任务查询)执行完毕后,关闭进度界面。
2、关键实现代码片段
2-1、UI界面类
using System;
using System.Linq;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Threading;
using SmartDeviceProjectWtms.Domain;
using SmartDeviceProjectWtms.Repository;
using System.Windows.Forms;
namespace SmartDeviceProjectWtms.Forms
{
public partial class FrmProcessModel : Form
{
public FrmProcessModel()
{
InitializeComponent();
}
// 线程执行业务类型
// 0-钻井任务下载入库,1-质检任务下载入库
public int PROCESS_TYPE { get; set; }
// 线程执行业务数据
private string PROCESS_DATA { get; set; }
// 声明一个委托
private delegate void NewDelegate();
// 创建一个 Service新线程的方法
public void runCurrentThread()
{
Thread thread;
ThreadStart threadstart = new ThreadStart(startCase);
thread = new Thread(threadstart);
thread.Start();
}
// 创建一个 UI新线程的方法
public void runCurrentUIThread()
{
Thread thread;
ThreadStart threadstart = new ThreadStart(startUiCase);
thread = new Thread(threadstart);
thread.Start();
}
// 【UI处理】解决Control.Invoke 必须用于与在独立线程上创建的控件交互
private void startUiCase()
{
if (InvokeRequired)
{
// 要 努力 工作的 方法
BeginInvoke(new NewDelegate(changeUI));
}
}
// 【远程处理】解决Control.Invoke 必须用于与在独立线程上创建的控件交互
private void startCase()
{
if (InvokeRequired)
{
// 要 努力 工作的 方法
if (this.PROCESS_TYPE == 0)
{
BeginInvoke(new NewDelegate(SaveRemoteDrillingTasks));
}
else if (this.PROCESS_TYPE == 1)
{
BeginInvoke(new NewDelegate(SaveRemoteQualityTasks));
}
}
}
/// <summary>
/// 【UI动态改变】随机切换显示图片
/// </summary>
private void doChangePictures()
{
Image imageA = pictureBox0.Image;
Image imageB = pictureBox1.Image;
//实例化随机数产生器random;
Random rad = new Random();
// 生成大于0小于11的随机数
int value = rad.Next(0, 11);
if (value % 2 == 0)
{
pictureBox0.Image = imageA; pictureBox2.Image = imageA;
pictureBox4.Image = imageA; pictureBox6.Image = imageA;
pictureBox1.Image = imageB; pictureBox3.Image = imageB;
pictureBox5.Image = imageB; pictureBox7.Image = imageB;
}
else
{
pictureBox0.Image = imageB; pictureBox2.Image = imageB;
pictureBox4.Image = imageB; pictureBox6.Image = imageB;
pictureBox7.Image = imageA; pictureBox1.Image = imageA;
pictureBox3.Image = imageA; pictureBox5.Image = imageA;
}
}
// 【UI处理显示】改变UI图片循环展示
private void changeUI()
{
int index = 0;
while (Global.QUEST_STATUS && index <= Global.PROCESS_LOOP_COUNT)
{
Thread.Sleep(Global.PROCESS_LOOP_FEQUENCE);
doChangePictures();
Application.DoEvents();
index++;
}
// 关闭此窗口
this.Close();
}
/// <summary>
/// 【UI切换&业务处理】启动并执行相应的操作类型
/// </summary>
public void toStartUI()
{
// 允许发起请求
Global.QUEST_STATUS = true;
// 执行UI线程
this.runCurrentUIThread();
// 执行业务线程
//this.runCurrentThread();
}
/******************************线程处理业务*******************************/
private readonly DrillingTaskRepository drillingTaskDao = new DrillingTaskRepository();
private static QualityTaskRepository qualityTaskDao = new QualityTaskRepository();
/// <summary>
/// 【钻井任务】添加到本地数据库
/// </summary>
/// <returns></returns>
public void SaveRemoteDrillingTasks()
{
//获取服务器任务数据
List<DrillingTaskModel> modelList = RemoteDataService.GetRemoteToLocalDrillingTasksByJson();
if (modelList != null)
{
foreach (DrillingTaskModel model in modelList)
{
if (model != null)
{
// 添加任务到本地暂存SDF数据库
DrillingTask task = new DrillingTask(Convert.ToString(model.id), Convert.ToString(model.projectId), model.measureLineNo, model.wellsNo, model.wellsName, model.wellsLocation, Convert.ToString(model.latlngNorth), Convert.ToString(model.latlngEast), Convert.ToString(model.elevation), model.processStatus, model.planStartDate, model.taskEidtDate, model.captainName, model.areaName, model.projectCode);
try
{
drillingTaskDao.AddDrillingTask(task);
}
catch (Exception ex)
{
MessageBox.Show("钻井任务入库异常:" + ex.Message);
continue;
}
// 更新任务状态下载状态
int flag = 1;
flag = RemoteDataService.UpdateDrillingTasksDownloadStatus(task, flag);
if (flag == 0)
{
//更新失败删除本地数据库任务
try
{
drillingTaskDao.DeleteDrillingTaskByTaskId(task.TaskId);
}
catch (Exception ex)
{
MessageBox.Show("本地任务删除异常:" + ex.Message);
continue;
}
}
}
}
}
// 终止线程
Global.QUEST_STATUS = false;
ProcessThread.UN_QUIT_THREAD = false;
}
/// <summary>
/// 【质检任务】添加到本地数据库
/// </summary>
/// <returns></returns>
public void SaveRemoteQualityTasks()
{
//获取服务器任务数据
List<QualityTaskModel> modelList = RemoteDataService.GetRemoteToLocalQualityTasksByJson();
if (modelList != null)
{
foreach (QualityTaskModel model in modelList)
{
if (model != null)
{
// 添加任务到本地暂存SDF数据库
QualityTask task = new QualityTask(Convert.ToString(model.id), Convert.ToString(model.projectId), model.measureLineNo, model.wellsNo, model.processStatus, model.planEndDate, model.taskEidtDate, model.checker, model.areaName, model.projectCode);
try
{
qualityTaskDao.AddQualityTask(task);
}
catch (Exception ex)
{
MessageBox.Show("钻井任务入库异常:" + ex.Message);
continue;
}
// 更新任务下载状态
int flag = RemoteDataService.UpdateQualityTasksDownloadStatus(task.TaskId);
if (flag == 0)
{
//更新失败删除本地数据库任务
try
{
qualityTaskDao.DeleteQualityTaskByTaskId(task.TaskId);
}
catch (Exception ex)
{
MessageBox.Show("本地任务删除异常:" + ex.Message);
continue;
}
}
}
}
}
// 终止线程
Global.QUEST_STATUS = false;
ProcessThread.UN_QUIT_THREAD = false;
}
// 窗体活动事件
private void FrmProcessModel_Activated(object sender, EventArgs e)
{
this.toStartUI();
}
/// <summary>
/// 【钻井任务】查询远程数据库任务情况
/// </summary>
public void SearchDrillingList(string queryMeasureNo, string queryWellsNo, int queryProcess)
{
// 执行远程数据访问
Global.TEMP_DATA = RemoteDataService.GetRemoteDrillingTasksJsonByQueryParams(Global.DEVICE_CODE, queryMeasureNo, queryWellsNo, queryProcess);
// 终止线程
Global.QUEST_STATUS = false;
ProcessThread.UN_QUIT_THREAD = false;
}
/// <summary>
/// 【质检任务】查询远程数据库任务情况
/// </summary>
public void SearchQualityList(string queryMeasureNo, string queryWellsNo, int queryProcess)
{
// 执行远程数据访问
Global.TEMP_DATA = RemoteDataService.GetRemoteQualityTasksJsonByQueryParams(Global.DEVICE_CODE, queryMeasureNo, queryWellsNo, queryProcess);
// 终止线程
Global.QUEST_STATUS = false;
ProcessThread.UN_QUIT_THREAD = false;
}
}
}
2-2、UI线程委托
using System;
using System.Linq;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.Threading;
using SmartDeviceProjectWtms.Forms;
namespace SmartDeviceProjectWtms
{
public class ProcessThread
{
public static bool UN_QUIT_THREAD = true;
private static ProcessThread _instance;
private static readonly Object syncLock = new Object();
public static ProcessThread Instance
{
get
{
if (ProcessThread._instance == null)
{
lock (syncLock)
{
if (ProcessThread._instance == null)
{
ProcessThread._instance = new ProcessThread();
}
}
}
return ProcessThread._instance;
}
}
private ProcessThread()
{
}
private Thread waitingThread;
private FrmProcessModel waitingForm;
public void CreateForm()
{
if (waitingThread != null && waitingForm != null)
{
try
{
waitingThread.Abort();
}
catch (Exception)
{
}
}
waitingThread = new Thread(new ThreadStart(delegate()
{
waitingForm = new FrmProcessModel();
Application.Run(waitingForm);
}));
waitingThread.Start();
}
public FrmProcessModel GetForm()
{
return waitingForm;
}
public void CloseForm()
{
if (waitingThread != null)
{
try
{
waitingThread.Abort();
}
catch (Exception)
{
}
}
}
}
}
2-3、主线程调用
private void funcQualityBtn_Click(object sender, EventArgs e)
{
string message = "";
ProcessThread.UN_QUIT_THREAD = true;
switch (Global.DEVICE_STATUS)
{
case 0:
message = "禁用";
break;
case 1:
// 打开处理进度条
this.operateType = 1;
ProcessThread processThread = ProcessThread.Instance;
processThread.CreateForm();
// 睡眠一会儿等待创建进度显示窗口
Thread.Sleep(300);
// 远程数据处理
while (ProcessThread.UN_QUIT_THREAD)
{
processThread.GetForm().SaveRemoteQualityTasks();
Application.DoEvents();
processThread.CloseForm();
// 打开质检窗口主页
FrmQualityMain frmQualityMain = new FrmQualityMain();
frmQualityMain.Show();
}
return;
case 2:
message = "归还";
break;
case 3:
message = "损坏";
break;
}
MessageBox.Show("设备已【" + message + "】,操作无效!");
}
注意:调用时Thread.sleep(300);的位置。设置此休眠是因为:在while之前窗体还没有被创建,所以为了防止空引用故设置之。如果将Thread.sleep(300);放在while循环内第一行,webservice就会陷入无休止的循环请求中,所以要放置在外面。