实例介绍
【实例简介】
【实例截图】
【核心代码】
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading;
using Debug = System.Diagnostics.Debug;
namespace Piao
{
public partial class MainForm : Form
{
private delegate void UpdateFormControlDelegate(object arg);
Func<Image, string> captchaHandle;//initialized in ctor.
private static Mutex threadMutex = new Mutex(false, "{69082C9C-0783-41B8-BC32-BD5556F10D09}");
DateTime lastPress = DateTime.Today;
string pressed = string.Empty;
int WORKER_TIMEOUT_MINUTES = 60;
int ORDER_DAY_AHEAD = 11;
Win7ProcessIcon win7SuperIcon = new Win7ProcessIcon();
public MainForm()
{
InitializeComponent();
InitializeBackgroundWorker();
InitializeControlsFromSetting();
InitializeCaptchaDelegate();
#if DEBUG
this.Text = " - DEBUG VERSION";
#endif
}
private void txt_userFromStation_Autocompletion(object sender, KeyPressEventArgs e)
{
ComboBox box = (sender as ComboBox);
BindingSource filterSource = box.DataSource as BindingSource;
if (filterSource == null)
return;
//reset all columns
if (e.KeyChar == (char)Keys.Escape)
{
if (box.SelectedIndex > 0)
{
string text = box.Text;
filterSource.Filter = string.Empty;
box.Text = text;
}
else
filterSource.Filter = string.Empty;
e.Handled = true;
return;
}
//only accept valid input [a-zA-Z]
//65-90 97-122
bool onlyLetters = (e.KeyChar >= (char)65 && e.KeyChar <= (char)90) || (e.KeyChar >= (char)97 && e.KeyChar <= (char)122);
if (!onlyLetters)
return;
//timeout to clear cached input
TimeSpan ts = DateTime.Now - lastPress;
if (ts.TotalSeconds > 1)
{
pressed = string.Empty;
}
lastPress = DateTime.Now;
pressed = e.KeyChar.ToString().ToUpper();
//dont use empty data source , the combox will throw ArgumentOutofRangeException
//before that there is an empty row added in the table, it will be default item when search has no result
string searchQuery = string.Format("[{0}] like '{1}%'", Global.DataComlumnPinYin, pressed);
if (Global.StationNameTable.Select(searchQuery).Length == 0)
searchQuery = string.Format("[{0}] is null", Global.DataComlumnPinYin);
Log.Debug("filter by {0}", searchQuery);
filterSource.Filter = searchQuery;
//only handle the first char for navigation
if (pressed.Length != 1)
e.Handled = true;
Debug.WriteLine(pressed);
}
private void txt_webCaptcha_KeyPressForFilter(object sender, KeyPressEventArgs e)
{
if (e.KeyChar == (char)Keys.Back || e.KeyChar == (char)Keys.Delete)
return;
if (txt_webCaptcha.Text.Length >= 4)
{
e.Handled = true;
return;
}
if ((e.KeyChar < '0' && e.KeyChar > '9')
|| (e.KeyChar < 'a' && e.KeyChar > 'z')
|| (e.KeyChar < 'A' && e.KeyChar > 'Z')
|| (e.KeyChar == ' ')
)
e.Handled = true;
}
/// <summary>
/// read server city names.
/// </summary>
private void StartPrep()
{
Log.Debug("start:after logon init.");
UpdateFormControlDelegate initialzeStationThreadDelegate = new UpdateFormControlDelegate(arg =>
{
if (Global.StationNameDict.Count == 0)
{
MessageBox.Show("未能初始化,关闭并重启窗口再试。", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
try
{
//here assign data source only once
if (txt_userFromStation.DataSource == null)
{
Log.Debug("apply data source to controls");
BindingSource bindSourceFrom = new BindingSource();
BindingSource bindSourceTo = new BindingSource();
//use different data source
bindSourceFrom.DataSource = Global.StationNameTable;
bindSourceTo.DataSource = Global.StationNameTable.Copy();
txt_userFromStation.DataSource = bindSourceFrom;
txt_userFromStation.ValueMember = Global.DataComlumnDisplayText;
txt_userToStation.DataSource = bindSourceTo;
txt_userToStation.ValueMember = Global.DataComlumnDisplayText;
}
txt_userFromStation.Enabled = true;
txt_userToStation.Enabled = true;
txt_userFromStation.Text = Configurations.txt_userFromStation;
txt_userToStation.Text = Configurations.txt_userToStation;
}
catch (Exception exc)
{
Log.Debug(exc.ToString());
}
});
UpdateFormControlDelegate initialzeSeatTypesThreadDelegate = new UpdateFormControlDelegate(arg =>
{
Log.Debug("refresh seat types.");
List<JsonObject> list = arg as List<JsonObject>;
if (list == null || list.Count == 0)
return;
try
{
foreach (JsonObject obj in list)
{
if (chk_userSeatTypes.Items.Contains(obj.value) == false)
{
chk_userSeatTypes.Items.Add(obj.value);
}
}
if (chk_userSeatTypes.Items.Count > 2)
{
chk_userSeatTypes.SetItemChecked(0, true);
chk_userSeatTypes.SetItemChecked(1, true);
}
Log.Debug("end:select first seat as default.");
txt_userToStation_QueryStStrainAll(txt_userToStation, EventArgs.Empty);
}
catch (Exception exc)
{
Log.Debug(exc.ToString());
}
});
UpdateFormControlDelegate initialzeControlDisplayThreadDelegate = new UpdateFormControlDelegate(arg =>
{
Log.Debug("end:app init is complete.");
menu_status.Text = "Ready";
this.TopMost = false;
group_captcha.Enabled = true;
group_login.Enabled = true;
group_ticket.Enabled = true;
group_webform.Enabled = true;
});
Thread thPrep = new Thread(() =>
{
int i = 0;
while (i < 2)
{
if (Global.StationNameDict.Count == 0)
UserOpration.Instance.QueryStationName();
else if (Global.TicketCodeList.Count == 0)
UserOpration.Instance.QuerySeatTypes();
else
break;
CheckThreadStateToAbort();
Thread.Sleep(1000);
}
this.Invoke(initialzeStationThreadDelegate, Global.StationNameDict);
this.Invoke(initialzeSeatTypesThreadDelegate, Global.TicketCodeList);
this.Invoke(initialzeControlDisplayThreadDelegate, "");
});
thPrep.Start();
}
private void btn_login_Click(object sender, EventArgs e)
{
Log.Debug("start:log in");
this.btn_login.Enabled = false;
txt_webCaptcha.Focus();
string user = txt_userWebName.Text;
string pwd = txt_userWebPassword.Text;
UpdateFormControlDelegate loginComplete = new UpdateFormControlDelegate(arg =>
{
string welcomename = arg as string;
user_imageBox.Image = null;
lbl_userCaptchaInfo.Text = string.Empty;
txt_webCaptcha.Text = null;
btn_login.Enabled = true;
btn_login.Focus();
if (!string.IsNullOrEmpty(welcomename))
{
this.Text = arg.ToString();
menu_status.Text = "登陆成功";
menu_start.ForeColor = Color.Red;
menu_start.Enabled = true;
StartPrep();
Log.Message("已登陆, 等待加载成功后点击 {0} 刷新; 站名首字母查询不支持多音字。", menu_start.Text);
}
Log.Debug("log in action is complete.");
});
Thread waitInputThread = new Thread(() =>
{
string propmtString = string.Empty;
for (int i = 0; i < int.MaxValue; i )
{
//retry logon for 3 times if failed
propmtString = UserOpration.NewInstance().Login(captchaHandle, user, pwd);
if (!string.IsNullOrEmpty(propmtString))
break;
}
this.Invoke(loginComplete, propmtString);
});
waitInputThread.SetApartmentState(ApartmentState.STA);
waitInputThread.Start();
}
private void txt_userToStation_QueryStStrainAll(object sender, EventArgs e)
{
if (txt_userToStation.SelectedIndex < 0 ||
txt_userFromStation.SelectedIndex < 0 ||
string.IsNullOrEmpty(txt_userToStation.Text) ||
string.IsNullOrEmpty(txt_userFromStation.Text))
return;
if (txt_dateTimePicker.Value <= DateTime.Today)
{
Log.Error("日期需要大于今日. ");
return;
}
Log.Debug("start:search trains.");
txt_userTrains.Items.Clear();
txt_userTrains.Enabled = false;
txt_userOrderTrainName.Text = string.Empty;
txt_userOrderTicketLeft.Text = string.Empty;
string day = txt_dateTimePicker.Value.ToString("yyyy-MM-dd");
//first one is initial letter for index
string fromText = txt_userFromStation.Text.Split(',')[1];
string toText = txt_userToStation.Text.Split(',')[1];
//already in dropdown so index won't be out of bound.
string fromCode = FindCodeByChineseName(fromText);
string toCode = FindCodeByChineseName(toText);
if (fromCode == toCode) return;
if (txt_userFromStation.SelectedIndex < 0 || txt_userToStation.SelectedIndex < 0)
{
txt_userTrains.Enabled = false;
return;
}
SetWorkStatus(true);
UpdateFormControlDelegate initializeTrainListThreadDelegate = new UpdateFormControlDelegate(arg =>
{
try
{
Log.Debug("start:set data to controls for seat types.");
Comparison<JsonObject> compareDelegate = delegate(JsonObject x, JsonObject y)
{
if (x.value[0] == y.value[0])
{ return 0; }
int result = x.value[0] > y.value[0] ? -1 : 1;
return result;
};
List<object> extraNames = new List<object>();
List<JsonObject> source = arg as List<JsonObject>;
source.Sort(compareDelegate);
foreach (JsonObject item in source)
{
if (item.end_station_name == toText) //put exact match to the beginning and put the rest to end
txt_userTrains.Items.Add(item.value);
else
extraNames.Add(item.value);
}
txt_userTrains.Items.AddRange(extraNames.ToArray<object>());
if (txt_userTrains.Items.Count > 0)
{
txt_userTrains.Enabled = true;
if (txt_userTrains.Items.Contains(Configurations.txt_userTrains))
{
txt_userTrains.SelectedItem = Configurations.txt_userTrains;
}
else
txt_userTrains.SelectedIndex = 0;
Log.Debug("end:retrieve train list is complete.");
txt_userTrains.Focus();
}
else
{
Log.Error("[{0}] 到 [{1}] 车次信息暂无。", fromText, toText);
}
}
catch (Exception ex)
{
Log.Debug(ex.ToString());
}
finally
{
SetWorkStatus(false);
}
});
Thread thPrep = new Thread(() =>
{
if (threadMutex.WaitOne(TimeSpan.Zero))
{
try
{
object stationData = UserOpration.Instance.QueryStStrainAll(day, fromCode, toCode);
this.Invoke(initializeTrainListThreadDelegate, stationData);
}
finally
{
threadMutex.ReleaseMutex();
}
}
else
{
Log.Debug("Thread is busy, job of this thread is aborted. from {0} to {1}", fromText, toText);
}
});
thPrep.SetApartmentState(ApartmentState.STA);
thPrep.Start();
}
/// <summary>
/// get train info by id.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void txt_userTrains_QueryLeftTickets(object sender, EventArgs e)
{
if (txt_dateTimePicker.Value <= DateTime.Today)
{
Log.Error("日期需要大于今日. ");
return;
}
lst_trainDetail.Items.Clear();
txt_userOrderTicketLeft.Text = "";
txt_userOrderTrainName.Text = "";
if (txt_userTrains.SelectedIndex < 0)
{
this.lst_trainDetail.Tag = null;
return;
}
Log.Debug("start:query left tickets");
string trainId = txt_userTrains.SelectedItem.ToString();
var train = Global.TrainCodeList.Find(t => t.value == trainId);
if (train == null)
{
this.lst_trainDetail.Tag = null;
return;
}
try
{
SetWorkStatus(true);
//query left ticket
string day = txt_dateTimePicker.Value.ToString("yyyy-MM-dd");
string from = FindCodeByChineseName(txt_userFromStation.Text.Split(',')[1]);
string to = FindCodeByChineseName(txt_userToStation.Text.Split(',')[1]);
//set data tag
OrderData odata = new OrderData()
{
station_train_code = train.value,
train_date = day,
seattype_num = "",
from_station_telecode = from,
to_station_telecode = to,
include_student = "00",
from_station_telecode_name = "始发站",
to_station_telecode_name = "目的站",
round_train_date = "",
round_start_time_str = "00:00--24:00",
single_round_type = "1",
train_pass_type = "QB",
train_class_arr = "QB#D#Z#T#K#QT#",
start_time_str = "00:00--24:00",
lishi = train.lishi,
train_start_time = train.start_time,
trainno = train.id,
arrive_time = "15:42",
from_station_name = "始发站",
to_station_name = "目的站",
ypInfoDetail = train.ypInfoDetail,
};
txt_userOrderTrainName.Text = train.value;
//station chinese name to code after output
bool result = UserOpration.Instance.QueryLeftTicket(day, ref from, ref to, train.id, ref odata);
txt_userOrderTicketLeft.Text = result ? "有" : "无";
Log.Debug("end: query left ticket, attach object data to tag.");
//update listview with property 'lishi'
var propList = train.GetType().GetFields(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance);
foreach (var p in propList)
{
string val = p.GetValue(train) as string;
var item = new ListViewItem(p.Name);
item.SubItems.Add(val);
lst_trainDetail.Items.Add(item);
}
this.lst_trainDetail.Tag = odata;
}
catch (Exception ex)
{
Log.Debug(ex.ToString());
}
finally
{ SetWorkStatus(false); }
}
private void menu_start_Click(object sender, EventArgs e)
{
Log.Debug("start:timer enabled for search.");
Global.SeatTypeTargets = new List<JsonObject>();
foreach (var checkeditem in chk_userSeatTypes.CheckedItems)
{
JsonObject obj = null;
if (
(obj = Global.TicketCodeList.Find(j => j.value == checkeditem.ToString()))
!= null)
{
Global.SeatTypeTargets.Add(obj);
continue;
}
}
if (Global.SeatTypeTargets.Count == 0)
{
MessageBox.Show("需要选择票类型", "Error");
return;
}
if (lst_trainDetail.Tag == null)
{
MessageBox.Show("需要选择一个列车, 等待加载或选择。", "Error");
return;
}
SetWorkStatus(true);
UserData user = new UserData();
//user.passenger_1_seat = tickets[0].id;
user.passenger_1_ticket = "1"; //成人
user.passenger_1_name = txt_userSeatName.Text;
user.passenger_1_cardtype = "1";//二代身份证
user.passenger_1_cardno = txt_userIdNumber.Text;
user.passenger_1_mobileno = txt_userSeatTel.Text;
this.backgroundWorker1.RunWorkerAsync(user);
}
private void menu_cancel_Click(object sender, EventArgs e)
{
Log.Debug("start:timer abort signal sent.");
if (this.backgroundWorker1.IsBusy)
{
this.backgroundWorker1.CancelAsync();
}
}
private void menu_ShowWebPage_Click(object sender, EventArgs e)
{
WebForm web = new WebForm();
web.Show();
}
void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
this.Invoke(new UpdateFormControlDelegate(a =>
{
win7SuperIcon.SetState(this.Handle, TBPFLAG.TBPF_NOPROGRESS);
Log.Message("##运行已经停止。##");
SetWorkStatus(false);
notifyIcon1.ShowBalloonTip(3000, "12306", "运行已经停止。", ToolTipIcon.Info);
}),
"");
}
void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker = sender as BackgroundWorker;
OrderData odata = lst_trainDetail.Tag as OrderData;
UserData user = e.Argument as UserData;
if (user == null)
{
return;
}
Log.Message("开始运行, 查询超时约{1}分钟后停止, 点击 {0} 可以立刻停止。", menu_cancel.Text, WORKER_TIMEOUT_MINUTES);
System.Diagnostics.Stopwatch watch = new System.Diagnostics.Stopwatch();
watch.Start();
bool result = false;
while (watch.Elapsed.TotalMinutes < WORKER_TIMEOUT_MINUTES)
{
if ((worker.CancellationPending == true))
{
e.Cancel = true;
break;
}
else
{
result = UserOpration.Instance.QueryLeftTicket(odata.train_date,
ref odata.from_station_telecode,
ref odata.to_station_telecode,
odata.trainno,
ref odata);
if (result)
break;
Thread.Sleep(1000);
}
int percent = (int)(100 * watch.Elapsed.TotalMinutes / WORKER_TIMEOUT_MINUTES);
percent = percent < 30 ? 30 : percent; //for virsual effort set to 30%
worker.ReportProgress(percent);
}
if (result == false)
{
Log.Error("车次信息不可用, 停止提交。 ");
return;
}
UserOpration.Instance.SubmitOrderRequest(odata, user, captchaHandle);
}
private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
win7SuperIcon.SetState(this.Handle, TBPFLAG.TBPF_NORMAL);
win7SuperIcon.SetProgress(this.Handle, (ulong)e.ProgressPercentage, 100);
}
protected override void OnClosing(CancelEventArgs e)
{
menu_cancel_Click(menu_cancel, null);
if (txt_userFromStation.Text != null)
Configurations.txt_userFromStation = txt_userFromStation.Text.ToString();
if (txt_userToStation.Text != null)
Configurations.txt_userToStation = txt_userToStation.Text.ToString();
if (txt_userTrains.Text != null)
Configurations.txt_userTrains = txt_userTrains.Text.ToString();
Properties.Settings.Default.Save();
Configurations.Save();
base.OnClosing(e);
}
#region private func
private void SetWorkStatus(bool isworking = true)
{
menu_status.Text = isworking ? "正在查询" : "Ready";
menu_start.Enabled = !isworking;
group_login.Enabled = !isworking;
group_webform.Enabled = !isworking;
menu_cancel.Enabled = isworking;
}
private void InitializeControlsFromSetting()
{
string procName = System.Diagnostics.Process.GetCurrentProcess().ProcessName;
int pCount = System.Diagnostics.Process.GetProcessesByName(procName).Length - 1;
this.StartPosition = FormStartPosition.Manual;
this.Location = new Point(
Screen.PrimaryScreen.WorkingArea.Width - Width - 400 * pCount,
100 * pCount);
this.Icon = Icon.ExtractAssociatedIcon(Environment.ExpandEnvironmentVariables("%windir%" @"\system32\winver.exe"));
this.notifyIcon1.Icon = this.Icon;
txt_dateTimePicker.Value = DateTime.Today.Add(new TimeSpan(ORDER_DAY_AHEAD, 0, 0, 0));
chk_userSeatTypes.Items.AddRange(Configurations.chk_userSeatTypes.Split(','));
Log.Add(new FormLog(this.txt_log));
foreach (string p in Properties.Settings.Default.webProxy)
{
ToolStripMenuItem menuItem = new ToolStripMenuItem(p);
menuItem.Click = (object sender, EventArgs e) =>
{
foreach (ToolStripMenuItem i in Proxy_toolStripMenuItem.DropDownItems)
{
i.CheckState = CheckState.Unchecked;
}
ToolStripMenuItem item = sender as ToolStripMenuItem;
item.CheckState = CheckState.Checked;
UserOpration.Instance.ProxyName = item.Text;
};
Proxy_toolStripMenuItem.DropDownItems.Add(menuItem);
}
KeyPressEventHandler submitHandler = delegate(object sender, KeyPressEventArgs e)
{
if (e.KeyChar == (char)Keys.Enter)
{
btn_login_Click(btn_login, EventArgs.Empty);
e.Handled = true;
}
};
txt_userWebName.KeyPress = submitHandler;
txt_userWebPassword.KeyPress = submitHandler;
}
private void InitializeCaptchaDelegate()
{
UpdateFormControlDelegate updateImage = new UpdateFormControlDelegate(arg =>
{
if (!cb_autoCaptcha.Checked)
{
this.BringToFront();
this.Activate();
txt_webCaptcha.Focus();
}
user_imageBox.Image = arg as Image;
lbl_userCaptchaInfo.Text = "60秒内输入验证码, 不区分大小写。";
});
UpdateFormControlDelegate clearCaptchaCode = new UpdateFormControlDelegate(arg =>
{
this.TopMost = false;
txt_webCaptcha.Text = string.Empty;
user_imageBox.Image = null;
lbl_userCaptchaInfo.Text = string.Empty;
});
UpdateFormControlDelegate updateAutoCaptcha = new UpdateFormControlDelegate(arg =>
{
txt_webCaptcha.Text = arg as string;
});
captchaHandle = (img) =>
{
if (img == null)
{
Log.Error("出现错误, 不能获取验证码。 ");
return string.Empty;
}
ImageUtil.GrayImage(ref img);
this.Invoke(updateImage, img);
if (cb_autoCaptcha.Checked)
{
tessnet2.Tesseract tessocr = new tessnet2.Tesseract();
tessocr.SetVariable("tessedit_char_whitelist", "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ");
tessocr.Init(null, "eng", false); // To use correct tessdata
List<tessnet2.Word> result = tessocr.DoOCR(new Bitmap(img), Rectangle.Empty);
string _result = result[0].Text.Trim();
if(_result.Length<4)
{
_result = "1234";
}
this.Invoke(updateAutoCaptcha, _result);
//txt_webCaptcha.Text = result[0].Text.Trim();
Log.Error("验证码为:" result[0].Text.Trim() "置信度为:" result[0].Confidence);
}
else
{
Log.Error("!!!!!!!!! 输入验证码 !!!!!!!!!!!");
}
int i = 0;
while (i < 20)
{
Thread.Sleep(2000);
if (txt_webCaptcha.Text.Length >= 4)
break;
CheckThreadStateToAbort();
}
string ret = txt_webCaptcha.Text;
this.Invoke(clearCaptchaCode, "");
return ret;
};
}
private void InitializeBackgroundWorker()
{
this.backgroundWorker1.WorkerSupportsCancellation = true;
this.backgroundWorker1.DoWork = new DoWorkEventHandler(backgroundWorker1_DoWork);
this.backgroundWorker1.RunWorkerCompleted = new RunWorkerCompletedEventHandler(backgroundWorker1_RunWorkerCompleted);
}
private void CheckThreadStateToAbort()
{
if (this.IsDisposed || Thread.CurrentThread.ThreadState == ThreadState.AbortRequested)
Thread.CurrentThread.Abort();
}
private string FindCodeByChineseName(string name)
{
var rows = Global.StationNameTable.Select(string.Format("{0}='{1}'", Global.DataComlumnChineseName, name));
string code = rows[0][Global.DataComlumnCodeName] as string;
return code;
}
#endregion
}
}
好例子网口号:伸出你的我的手 — 分享!
小贴士
感谢您为本站写下的评论,您的评论对其它用户来说具有重要的参考价值,所以请认真填写。
- 类似“顶”、“沙发”之类没有营养的文字,对勤劳贡献的楼主来说是令人沮丧的反馈信息。
- 相信您也不想看到一排文字/表情墙,所以请不要反馈意义不大的重复字符,也请尽量不要纯表情的回复。
- 提问之前请再仔细看一遍楼主的说明,或许是您遗漏了。
- 请勿到处挖坑绊人、招贴广告。既占空间让人厌烦,又没人会搭理,于人于己都无利。
关于好例子网
本站旨在为广大IT学习爱好者提供一个非营利性互相学习交流分享平台。本站所有资源都可以被免费获取学习研究。本站资源来自网友分享,对搜索内容的合法性不具有预见性、识别性、控制性,仅供学习研究,请务必在下载后24小时内给予删除,不得用于其他任何用途,否则后果自负。基于互联网的特殊性,平台无法对用户传输的作品、信息、内容的权属或合法性、安全性、合规性、真实性、科学性、完整权、有效性等进行实质审查;无论平台是否已进行审查,用户均应自行承担因其传输的作品、信息、内容而可能或已经产生的侵权或权属纠纷等法律责任。本站所有资源不代表本站的观点或立场,基于网友分享,根据中国法律《信息网络传播权保护条例》第二十二与二十三条之规定,若资源存在侵权或相关问题请联系本站客服人员,点此联系我们。关于更多版权及免责申明参见 版权及免责申明


网友评论
我要评论