protected virtual void OnFrameLoadComplete(FrameLoadCompleteEventArgs e) { FrameLoadComplete?.Invoke(this, e); // 原本是 //FrameLoadCompleteEventHandler handler = FrameLoadComplete; //if (handler != null) //{ // handler(this, e); //} }
public void HotKey_Ctrl_G() { log.Info($" "); log.Info("==========================================================================="); fm.FrameLoadComplete += F_LoadCompleted; log.Debug("@@ add delegate F_LoadCompleted."); //this.g.Navigate(DEFAULT_URL); // 20210720 加上延遲, 理由: 可能delegate還沒登記好, 就已經網頁更新好了 Thread.Sleep(150); // deactivate hotkeys 2 Deactivate_Hotkeys(); FrameLoadCompleteEventArgs ex = new FrameLoadCompleteEventArgs() { Message = FrameLoadStates.DirectCall }; F_LoadCompleted(this, ex); }
private void F_Data_LoadCompleted(object sender, FrameLoadCompleteEventArgs e) { log.Debug($"++ Enter F_Data_LoadCompleted from {e.Message}."); if (e.Message == FrameLoadStates.DocumentLoadCompletedButNotFrame) { return; } // 每當刷新後都要重新讀一次 // d 是parent HTML document HTMLDocument d = (HTMLDocument)g.Document; #region 感知目前位置, 與current_op比較, 如果不是,就還是要再按一次 // 目標: current_op.TAB_ID // 實際: d.getElementById(current_op.TAB_ID.Replace("_a_", "_li_")).className == "active" if (d.getElementById(current_op.TAB_ID.Replace("_a_", "_li_")).className != "active") { // 不active反而可以用按鍵, 自動會觸發F_Data_LoadCompleted // 20210719 有時候不fire Thread.Sleep(150); d.getElementById(current_op.TAB_ID).click(); log.Info($"[Action] push TAB {current_op.TAB_ID} Button."); log.Debug($"++ Exit F_Data_LoadCompleted (1/4). Not in the right page, click again."); return; } #endregion /// 20210719: 將QDATE設定為1901/1/1, 是傳達這是最後一頁了, 設定在F_Pager_LoadCompleted /// 20210719: 刪除掉蠢蠢的current_op?.QDate = 1901/1/1 ///if (current_op?.QDate == DateTime.Parse("1901/01/01")) ///{ /// // 不用再讀取資料了, 直接到存入資料庫部分 /// log.Info($"Entered F_Data_LoadCompleted, {current_op?.UID} 已經讀完所有資料, 最後存入資料庫."); ///} ///else ///{ /// 還需要讀取資料 log.Info($"Current OP: {current_op?.UID} {current_op?.Short_Name}"); //} log.Debug($"@@ delete delegate F_Data_LoadComplated. [{current_op?.UID}]"); fm.FrameLoadComplete -= F_Data_LoadCompleted; // 這時候已經確保是 active // f 是frame(0) HTML document HTMLDocument f = d?.frames.item(0).document.body.document; /// 3. 網頁操弄與擷取資料: sequential /// 3-1. 判斷分頁, 有幾頁, 現在在第幾頁, 換頁不會觸發LoadCompleted; 疑問會不會來不及? -done /// 3-2. 要先排序, 排序也不會觸發LoadCompleted; 疑問會不會來不及? -done, 不用再管排序 /// 3-2. 都放在記憶體裡, 快速, in the LIST /// // special remark: current_op.QDate set to null 是表示來自多頁結束那裏 // 20210719: 將QDATE設定為1901/1/1, 是傳達這是最後一頁了, 設定在F_Pager_LoadCompleted // 20210719: 刪除掉蠢蠢的current_op?.QDate = 1901/1/1 //if ((current_op != null) && (current_op?.QDate != DateTime.Parse("1901/01/01"))) if (current_op != null) { // 表示不是最後一頁, 還要讀取資料 log.Info($"[Action] Reading HTML: {current_op.Short_Name}, [{current_op?.UID}]"); #region 讀取資料, 存入記憶體, 存入檔案 foreach (Target_Table tt in current_op.Target) { // 是否有多tables, 端看tt.Children, 除了管制藥物外, 其餘都不用 if (tt.Children == null) { try { // 20210718: 好像就是這裏出了問題 ListRetrieved.Add(new VPN_Retrieved(tt.Short_Name, tt.Header_Want, f.getElementById(tt.TargetID).outerHTML, current_op.UID, current_op.QDate)); // 20200606 stop recording tables in html // 20210716 resume recording tables in html SaveHTML($"{tt.Short_Name}_{current_op.UID}", f.getElementById(tt.TargetID).outerHTML); } catch (Exception ex) { // 存入空的HTML ListRetrieved.Add(new VPN_Retrieved(tt.Short_Name, tt.Header_Want, "", current_op.UID, current_op.QDate)); log.Error($" Failed to read html. From: {tt.Short_Name}. Error: {ex.Message}"); } } else { // 有多個table, 使用情形僅有管制藥物 ListRetrieved.Add(new VPN_Retrieved(tt.Short_Name, tt.Header_Want, f.getElementById(tt.TargetID).children(tt.Children).outerHTML, current_op.UID, current_op.QDate)); SaveHTML($"{tt.Short_Name}_{tt.Children}_{current_op.UID}", f.getElementById(tt.TargetID).outerHTML); } } #endregion 讀取資料, 存入記憶體, 存入檔案 #region 判斷多頁 // 目前重點, 如何判斷多頁? // 設定total_pages = ???? HtmlDocument p = new HtmlDocument(); if (f.getElementById(@"ctl00$ContentPlaceHolder1$pg_gvList_input") == null) { log.Info($"[Info] Only one page detected, {current_op?.UID} {current_op?.Short_Name}."); total_pages = 1; } else { // 如果多頁, 轉換loadcomplete, 呼叫pager by click // 20200502: outerHTML的XPATH="//selection/option", innerHTML的XPATH="//option" p.LoadHtml(f.getElementById(@"ctl00$ContentPlaceHolder1$pg_gvList_input").innerHTML); HtmlNodeCollection o = p.DocumentNode.SelectNodes("//option"); total_pages = o.Count; log.Info($"[Info] {total_pages} pages detected, {current_op?.UID} {current_op?.Short_Name}"); // 剛剛已經讀了第一頁了, 從下一頁開始 current_page = 2; // 按鈕機制 fm.FrameLoadComplete += F_Pager_LoadCompleted; // 轉軌 log.Debug($"@@ add delegate F_Pager_LoadCompleted."); Thread.Sleep(150); foreach (IHTMLElement a in f.getElementById("ContentPlaceHolder1_pg_gvList").all) { if (a.innerText == ">") { log.Info("[Action] 按了下一頁."); log.Debug($"++ Exit F_Data_LoadCompleted (2/4). Multipage, go to next page."); a.click(); // 20200504 發現這裡執行完後還會執行後面的程序, 造成兩個程序的衝突 // 此段程式的一個出口點 return; } } } #endregion 判斷多頁 } // 判斷是否最後一tab, 程序群的出口 if (QueueOperation.Count == 0) { // 兩個出口之一, 最後一個tab, 另一個出口是, 最後一個tab, 同時沒有其他page, 另一個在F_Pager_LoadCompleted // 20210719: 讀完實體資料就開始解析HTML吧 string o = $"++ Exit F_Data_LoadCompleted (3/4). The REAL END! [{current_op.UID}]"; ParsingTables(o); return; } else { // 下一個tab current_op = QueueOperation.Dequeue(); fm.FrameLoadComplete += F_Data_LoadCompleted; log.Debug($"@@ add delegate F_Data_LoadCompleted. [{current_op.UID}]"); Thread.Sleep(150); d.getElementById(current_op.TAB_ID).click(); log.Debug($"[Action] {current_op.TAB_ID} tab key pressed. [{current_op.UID}]"); log.Debug($"++ Exit F_Data_LoadCompleted (4/4). Go to next tab. {QueueOperation.Count + 1} tabs to go.. [{current_op.UID}]"); return; } }
private void F_LoadCompleted(object sender, FrameLoadCompleteEventArgs e) { log.Debug($"++ Enter F_LoadCompleted from {e.Message}."); // 20200509 因為沒有先 -= F_LoadComplted, 造成了幽靈, 因此一定要 -= F_LoadComplted 在任何Exit之前. // 每次作業F_LoadCompleted只會被呼叫一次,沒有被洗掉的情形 fm.FrameLoadComplete -= F_LoadCompleted; log.Debug($"@@ delete delegate F_LoadCompleted."); // 使用DocumentLoadCompletedButNotFrame, 會造成偶而不動作的症狀, 要找別的方式來處理沒插健保卡的判別 // 方法 if (e.Message == FrameLoadStates.DocumentLoadCompletedButNotFrame) { // 沒有lbluserID, 例如沒插健保卡 // activate hotkeys 1 Activate_Hotkeys(); log.Debug($"++ Exit F_LoadCompleted (1/5). No NHI card inserted."); log.Info("==========================================================================="); log.Info($" "); return; } /// 會有兩次 /// 第一次讀完檔案會再執行javascript, 在local用來認證健保卡, 沒過就不會有第二次 /// 如果認證OK, 會再透過javascript下載個案雲端資料, 觸發第二次 /// 這段程式的目的: /// 1. 取得身分證字號 /// 2. 讀取有哪些tab // 20210719: mark this line to simplify logging // log.Info($"Entered F_LoadCompleted"); HTMLDocument d = (HTMLDocument)g.Document; // 確定身分證字號 string strUID = MakeSure_UID(d.getElementById("ContentPlaceHolder1_lbluserID").innerText); // if (strUID = string.Empty) 離開 if (strUID == string.Empty) { tb.ShowBalloonTip("醫療系統資料庫查無此人", "請與杏翔系統連動, 或放棄操作", BalloonIcon.Warning); // activate hotkeys 2 Activate_Hotkeys(); log.Debug($"++ Exit F_LoadCompleted (2/5). NHI card inserted but no such person."); log.Info("==========================================================================="); log.Info($" "); return; } else { /// 表示讀卡成功 /// show balloon with built-in icon tb.ShowBalloonTip("讀卡成功", $"身分證號: {strUID}", BalloonIcon.Info); log.Info($" Successful NHI card read, VPN id: {strUID}."); /// 讀卡成功後做三件事: 讀特殊註記, 讀提醒, 開始準備讀所有資料 /// 2. 讀取提醒, 如果有的話 /// 這是在ContentPlaceHolder1_GV /// 也是個table IHTMLElement List_NHI_lab_reminder = d?.getElementById("ContentPlaceHolder1_GV"); if (List_NHI_lab_reminder != null) { HtmlDocument Html_NHI_lab_reminder = new HtmlDocument(); Html_NHI_lab_reminder.LoadHtml(List_NHI_lab_reminder?.outerHTML); // 寫入資料庫 foreach (HtmlNode tr in Html_NHI_lab_reminder.DocumentNode.SelectNodes("//table/tbody/tr")) { HtmlDocument h_ = new HtmlDocument(); h_.LoadHtml(tr.InnerHtml); HtmlNodeCollection tds = h_.DocumentNode.SelectNodes("//td"); if ((tds == null) || (tds.Count == 0)) { continue; } string Lab_Name = string.Empty, Last_Date = string.Empty; // tds[0] 是檢查(驗)項目類別名稱 Lab_Name = tds[0]?.InnerText; // tds[1] 是最近1次檢查日期 Last_Date = tds[1]?.InnerText; using (Com_clDataContext dc = new Com_clDataContext()) { var q1 = from p1 in dc.tbl_NHI_lab_reminder where (p1.uid == strUID) && (p1.lab_name == Lab_Name) && (p1.last_date == Last_Date) select p1; if (q1.Count() == 0) { tbl_NHI_lab_reminder newReminder = new tbl_NHI_lab_reminder() { uid = strUID, QDATE = DateTime.Now, lab_name = Lab_Name, last_date = Last_Date }; dc.tbl_NHI_lab_reminder.InsertOnSubmit(newReminder); dc.SubmitChanges(); } }; } } /// 準備: 初始化, 欄位基礎資料/位置, 可在windows生成時就完成 #region 準備 - 製造QueueOperation // Initialization QueueOperation?.Clear(); ListRetrieved?.Clear(); current_page = total_pages = 0; log.Info($" start reading Operation(s)."); // 讀取所有要讀的tab, 這些資料位於"ContentPlaceHolder1_tab" // IHTMLElement 無法轉型為 HTMLDocument // 20200429 tested successful IHTMLElement List_under_investigation = d?.getElementById("ContentPlaceHolder1_tab"); // li 之下就是 a List <string> balloonstring = new List <string>(); string BalloonTip = string.Empty; foreach (IHTMLElement hTML in List_under_investigation?.all) { if (tab_id_wanted.Contains(hTML.id)) { // 僅將要讀入的排入, 並沒有真的讀取資料 VPN_Operation vOP = VPN_Dictionary.Making_new_operation(hTML.id, strUID, DateTime.Now); QueueOperation.Enqueue(vOP); log.Info($" 讀入operation: {vOP.Short_Name}, [{strUID}]"); balloonstring.Add(vOP.Short_Name); } } for (int i = 0; i < balloonstring.Count; i++) { if (i == 0) { BalloonTip = balloonstring[i]; } else if ((i % 3) == 0) { BalloonTip += $";\r\n{balloonstring[i]}"; } else { BalloonTip += $"; {balloonstring[i]}"; } } log.Info($" end of Reading Operation(s), 共{QueueOperation?.Count}個Operation(s)."); #endregion 準備 - 製造QueueOperation #region 執行 if (QueueOperation.Count > 0) { // 流程控制, fm = framemonitor // 載入第一個operation //log.Info($" the first operation loaded."); current_op = QueueOperation.Dequeue(); tb.ShowBalloonTip($"開始讀取 [{current_op.UID}]", BalloonTip, BalloonIcon.Info); // 判斷第一個operation是否active, (小心起見, 其實應該不可能不active) // 不active就要按鍵 // 要注意class這個attribute是在上一層li層, 需把它改過來 if (d.getElementById(current_op.TAB_ID.Replace("_a_", "_li_")).className == "active") { // 由於此時沒有按鍵, 因此無法觸發LoadComplete, 必須人工觸發 fm.FrameLoadComplete += F_Data_LoadCompleted; log.Debug($"@@ Add delegate F_Data_LoadCompleted."); FrameLoadCompleteEventArgs ex = new FrameLoadCompleteEventArgs() { Message = FrameLoadStates.DirectCall }; log.Debug($"++ Exit F_LoadCompleted (3/5). Goto F_Data_LoadCompleted by direct call."); F_Data_LoadCompleted(this, ex); return; } else { // 不active反而可以用按鍵, 自動會觸發F_Data_LoadCompleted fm.FrameLoadComplete += F_Data_LoadCompleted; log.Debug($"@@ Add delegate F_Data_LoadCompleted."); // 20210719 有時候不fire Thread.Sleep(150); d.getElementById(current_op.TAB_ID).click(); log.Info($"[Action] push TAB {current_op.TAB_ID} Button."); log.Debug($"++ Exit F_LoadCompleted (4/5). Go to next tab by pushing tab button."); return; } } else { // 做個紀錄 // 一個都沒有 log.Info($" no record at all."); tb.ShowBalloonTip("沒有資料", "健保資料庫裡沒有資料可讀取", BalloonIcon.Info); // 製作紀錄by rd tbl_Query2 q = new tbl_Query2() { uid = strUID, QDATE = DateTime.Now, cloudmed_N = 0, cloudlab_N = 0, schedule_N = 0, op_N = 0, dental_N = 0, allergy_N = 0, discharge_N = 0, rehab_N = 0, tcm_N = 0 }; using (Com_clDataContext dc = new Com_clDataContext()) { dc.tbl_Query2.InsertOnSubmit(q); dc.SubmitChanges(); }; // activate hotkeys 3 Activate_Hotkeys(); log.Debug($"++ Exit F_LoadCompleted (5/5). NHI inserted and verified but completey no data."); log.Info("==========================================================================="); log.Info($" "); } #endregion 執行 } }
private void F_Pager_LoadCompleted(object sender, FrameLoadCompleteEventArgs e) { log.Debug($"++ Entered F_Pager_LoadCompleted from {e.Message}"); if (e.Message == FrameLoadStates.DocumentLoadCompletedButNotFrame) { return; } log.Debug($"@@ delete delegate F_Pager_LoadComplated. [{current_op?.UID}]"); fm.FrameLoadComplete -= F_Pager_LoadCompleted; // 每當刷新後都要重新讀一次 // d 是parent HTML document HTMLDocument d = (HTMLDocument)g.Document; // f 是frame(0) HTML document HTMLDocument f = d.frames.item(0).document.body.document; // 讀取資料 foreach (Target_Table tt in current_op.Target) { // 這裡不用管多table, 因為多table只發生在管制藥那裏 ListRetrieved.Add(new VPN_Retrieved(tt.Short_Name, tt.Header_Want, f.getElementById(tt.TargetID).outerHTML, current_op.UID, current_op.QDate)); SaveHTML($"{tt.Short_Name}_{current_op.UID}", f.getElementById(tt.TargetID).outerHTML); } log.Info($"[Action] Reading HTML: {current_op.Short_Name}, [{current_op.UID}]. page: {current_page}/{total_pages}"); // 判斷是否最後一頁, 最後一tab if ((current_page == total_pages) && (QueueOperation.Count == 0)) { // 兩個出口之一, 最後一個tab, 另一個出口是, 最後一個tab, 同時有其他page且為最後一頁, // 另一個在F_Data_LoadCompleted // 最後一頁 // 處理index current_page = total_pages = 0; // 20200506: current_op 歸零似乎是不行的 //current_op = null; // 20210719: 將QDATE設定為1901/1/1, 是傳達這是最後一頁了, 設定在F_Pager_LoadCompleted // 20210719: 移除這個愚蠢的方法 //current_op.QDate = DateTime.Parse("1901/01/01"); //// 這是沒有用的add delegate, 但是為了平衡, 避免可能的錯誤 //fm.FrameLoadComplete += F_Data_LoadCompleted; //log.Info(" add delegate F_Data_LoadCompleted."); //// 沒有按鍵無法直接觸發, 只好直接呼叫 //FrameLoadCompleteEventArgs ex = new FrameLoadCompleteEventArgs() //{ // Message = FrameLoadStates.DirectCall //}; //F_Data_LoadCompleted(this, ex); // 此段程式的一個出口點 // 20210719: 讀完實體資料就開始解析HTML吧 string o = $"++ Exit F_Pager_LoadCompleted (1/3). last page, last tab, go to finalization directly. [{current_op.UID}]"; ParsingTables(o); return; } else if (current_page == total_pages) { // 最後一頁 // 處理index current_page = total_pages = 0; // 轉軌 fm.FrameLoadComplete += F_Data_LoadCompleted; log.Debug($"@@ add delegate F_Data_LoadCompleted. [{current_op.UID}]"); Thread.Sleep(150); // 下一個tab log.Info($"[Action] {current_op.TAB_ID} tab key pressed."); current_op = QueueOperation.Dequeue(); log.Debug($"++ Exit F_Pager_LoadCompleted (2/3). last page, go to next tab by clicking. [{current_op.UID}]"); d.getElementById(current_op.TAB_ID).click(); // 此段程式的一個出口點 return; } else { current_page++; // 按鍵到下一頁, 此段程式到此結束 // HOW TO ????????????????????????????????????????? // 如何下一頁, 可能要用invokescript // 按鈕機制 fm.FrameLoadComplete += F_Pager_LoadCompleted; log.Debug($"@@ add delegate F_Pager_LoadCompleted. [{current_op.UID}]"); Thread.Sleep(150); log.Info($"[Action] 下一頁按下去了.(多頁) [{current_op.UID}]"); log.Debug($"++ Exit F_Pager_LoadCompleted (3/3). go to next page by clicking. [{current_op.UID}]"); foreach (IHTMLElement a in f.getElementById("ContentPlaceHolder1_pg_gvList").all) { if (a.innerText == ">") { a.click(); } } // 此段程式的一個出口點 return; } }
private void TimersTimer_Elapsed(object sender, ElapsedEventArgs e) { w.Dispatcher.Invoke((Action)(() => { try { // readyState 是可以讀的 // 加event handler HTMLDocument d = (HTMLDocument)w.g.Document; HTMLDocument f = new HTMLDocument(); if (d.frames.length != 0) { // 有frame f = d.frames.item(0).document.body.document; new_dSTATE = d.readyState; new_fSTATE = f.readyState; if ((old_fSTATE == "loading" || old_fSTATE == "interactive" || old_fSTATE == "non-exist") && (new_fSTATE == "complete")) { // 20210719: mark this log to simplify logging //log.Debug($"***** frame readystate fired; f(old):{old_fSTATE} f(new):{new_fSTATE}; d(old):{old_dSTATE} d(new):{new_dSTATE}. *****"); //fSTATE = f?.readyState; // f is becoming ready FrameLoadCompleteEventArgs ex = new FrameLoadCompleteEventArgs() { Message = FrameLoadStates.FrameLoadCompleted }; OnFrameLoadComplete(ex); } } else { new_dSTATE = d.readyState; new_fSTATE = "non-exist"; if ((old_dSTATE == "loading" || old_dSTATE == "interactive") && (new_dSTATE == "complete")) { // 20210719: mark this log to simplify logging //log.Debug($"***** document only readystate fired; f(old):{old_fSTATE} f(new):{new_fSTATE}; d(old):{old_dSTATE} d(new):{new_dSTATE}. *****"); // f is not becoming ready, but d is becoming ready // this is like the situation of no NHI card FrameLoadCompleteEventArgs ex = new FrameLoadCompleteEventArgs() { Message = FrameLoadStates.DocumentLoadCompletedButNotFrame }; OnFrameLoadComplete(ex); } } //log.Debug($"Before Document:{old_dSTATE}, Frame:{old_fSTATE}; After Document:{new_dSTATE}, Frame:{new_fSTATE}"); old_dSTATE = new_dSTATE; old_fSTATE = new_fSTATE; //Debug.WriteLine($"before fSTATE={fSTATE}"); //Debug.WriteLine($"Main: {d.readyState}, Child: {f.readyState}"); //Debug.WriteLine($"after fSTATE={fSTATE}"); } catch (Exception) { // Do nothing // System.Windows.Forms.MessageBox.Show(ex.Message); //log.Error(ex.Message); //Debug.WriteLine(ex.Message); } })); }