크리스,
나는 여기에 문제를 해결하지만 얼굴 모든 것이 내가 기대 한대로 작동하기 전에 해결해야했다 그 아래에 아래에 설명 한 번 봐주세요 가능한 구현을 전달합니다.여기 웹 브라우저의 페이지에 대한 몇 가지 활동을하는 방법의 예합니다 (웹 브라우저 내 경우에는 양식의 일부임을 유의) :이 방법은 MMORPG의 페이지를 받아서 읽고 실제로
internal ActionResponse CheckMessages() //Action Response is a custom class of mine to store some data coming from pages
{
//go to messages
HtmlDocument doc = WbLink.Document; //wbLink is a referring link to a webBrowser istance
HtmlElement ele = doc.GetElementById("message_alert_box");
if (ele == null)
return new ActionResponse(false);
object obj = ele.DomElement;
System.Reflection.MethodInfo mi = obj.GetType().GetMethod("click");
mi.Invoke(obj, new object[0]);
semaphoreForDocCompletedEvent = WaitForDocumentCompleted(); //This is a simil-waitOne statement (1)
if (!semaphoreForDocCompletedEvent)
throw new Exception("sequencing of Document Completed events is failed.");
//get the list
doc = WbLink.Document;
ele = doc.GetElementById("mailz");
if (!ele.WaitForAvailability("mailz", Program.BrowsingSystem.Document, 10000)) //This is a simil-waitOne statement (2)
ele = doc.GetElementById("mailz");
ele = doc.GetElementById("mailz");
//this contains a tbody
HtmlElement tbody = ele.FirstChild;
//count how many elemetns are espionage reports, these elements are inline then counting double with their wrappers on top of them.
int spioCases = 0;
foreach (HtmlElement trs in tbody.Children)
{
if (trs.GetAttribute("id").ToLower().Contains("spio"))
spioCases++;
}
int nMessages = tbody.Children.Count - 2 - spioCases;
//create an array of messages to store data
GameMessage[] archive = new GameMessage[nMessages];
for (int counterOfOpenMessages = 0; counterOfOpenMessages < nMessages; counterOfOpenMessages++)
{
//open first element
WbLink.ScriptErrorsSuppressed = true;
ele = doc.GetElementById("mailz");
//this contains a tbody
tbody = ele.FirstChild;
HtmlElement mess1 = tbody.Children[1];
int idMess1 = int.Parse(mess1.GetAttribute("id").Substring(0, mess1.GetAttribute("id").Length - 2));
//check if subsequent element is not a spio report, in case it is then the element has not to be opened.
HtmlElement mess1Sibling = mess1.NextSibling;
if (mess1Sibling.GetAttribute("id").ToLower().Contains("spio"))
{
//this is a wrapper for spio report
ReadSpioEntry(archive, counterOfOpenMessages, mess1, mess1Sibling);
//delete first in line
DeleteFirstMessageItem(doc, ref ele, ref obj, ref mi, ref tbody);
semaphoreForDocCompletedEvent = WaitForDocumentCompleted(6); //This is a simil-waitOne statement (3)
}
else
{
//It' s anormal message
OpenMessageEntry(ref obj, ref mi, tbody, idMess1); //This opens a modal dialog over the page, and it is not generating a DocumentCompleted Event in the webBrowser
//actually opening a message generates 2 documetn completed events without any navigating event issued
//Application.DoEvents();
semaphoreForDocCompletedEvent = WaitForDocumentCompleted(6);
//read element
ReadMessageEntry(archive, counterOfOpenMessages);
//close current message
CloseMessageEntry(ref ele, ref obj, ref mi); //this closes a modal dialog therefore is not generating a documentCompleted after!
semaphoreForDocCompletedEvent = WaitForDocumentCompleted(6);
//delete first in line
DeleteFirstMessageItem(doc, ref ele, ref obj, ref mi, ref tbody); //this closes a modal dialog therefore is not generating a documentCompleted after!
semaphoreForDocCompletedEvent = WaitForDocumentCompleted(6);
}
}
return new ActionResponse(true, archive);
}
다른 플레이어가 계정에 보낸 메시지를 읽고 ReadMessageEntry 메서드를 통해 ActionResponse 클래스에 저장합니다.
실제로 대소 문자를 구별하고 유용하지 않은 코드의 구현과 논리를 제외하면 흥미로운 요소가 몇 가지 있습니다.
1) 페이지
2) 기본 문서를 얻을 수에 도착 : 나는
너 한테은 [문자 (1)
, (2)
및 (3)
로] 3 중요한 점을 코드에서 몇 가지 의견을 넣어 강조
다음 웹 브라우저
3) 메시지 페이지로 이동하기 위해 클릭 할 수있는 요소를 찾을에서 [HtmlElement ele = doc.GetElementById("message_alert_box");
으로 수행] 4) MethodInfo 인스턴스 및 반사 식 호출을 통해 클릭 이벤트 발생 [DocumentCompleted가 조만간 도착하도록 다른 페이지를 호출 함]
5) 완료된 문서가 수신 될 때까지 기다린 후 [으로 수행 : 시점 semaphoreForDocCompletedEvent = WaitForDocumentCompleted();
(1)]하여 진행하는
6) 페이지
7
을 변경 후) 웹 브라우저에서 새로운 문서를 페치 정의 된 페이지상의 특정 앵커를 찾을 위치를 메시지 I 읽으려는 경우
8) 해당 태그가 페이지 (일부 AJAX가 준비가되기 위해 읽고 싶은 것을 지연시킬 수 있기 때문에) [done : ele.WaitForAvailability("mailz", Program.BrowsingSystem.Document, 10000)
즉 point (2)]
9) 각 메시지를 읽기 위해 전체 루프를 수행합니다. 모달 대화 상자 양식은 동일한 페이지에 있으므로 DocumentCompleted를 생성하지 않습니다. 준비가되면 읽을 수 있도록 한 다음 닫고 다시 실행하십시오. 이 특별한 경우를 들어 I (1) 지점에서 semaphoreForDocCompletedEvent = WaitForDocumentCompleted(6);
라고의 오버로드를 사용 (3)
은 이제 일시 중지 확인하는 데 사용하는 세 가지 방법을 읽어
(1) DocumentCompleted없이 발생하면서 중지하려면
public static bool WaitForAvailability(this HtmlElement tag, string id, HtmlDocument documentToExtractFrom, long maxCycles)
{
bool cond = true;
long counter = 0;
while (cond)
{
Application.DoEvents(); //VERIFY trovare un modo per rimuovere questa porcheria
tag = documentToExtractFrom.GetElementById(id);
if (tag != null)
cond = false;
Thread.Yield();
Thread.SpinWait(100000);
counter++;
if (counter > maxCycles)
return false;
}
return true;
}
: (귀하의 경우로) 이상의 단일 목적을 위해 이용 될 수있다 DocumentCompleted 방법
private bool WaitForDocumentCompleted()
{
Thread.SpinWait(1000); //This is dirty but working
while (Program.BrowsingSystem.IsBusy) //BrowsingSystem is another link to Browser that is made public in my Form and IsBusy is just a bool put to TRUE when Navigating event is raised and but to False when the DocumentCOmpleted is fired.
{
Application.DoEvents();
Thread.SpinWait(1000);
}
if (Program.BrowsingSystem.IsInfoAvailable) //IsInfoAvailable is just a get property to cover webBroweser.Document inside a lock statement to protect from concurrent accesses.
{
return true;
}
else
return false;
}
(2) 페이지에서 사용할 수 있도록 특정 태그 기다립니다 과충전
(3) 프레임에 페이지를 다시로드 할 필요가 없어 DocumentCompleted를 기다리는 더러운 트릭!
private bool WaitForDocumentCompleted(int seconds)
{
int counter = 0;
while (Program.BrowsingSystem.IsBusy)
{
Application.DoEvents();
Thread.Sleep(1000);
if (counter == seconds)
{
return true;
}
counter++;
}
return true;
}
DocumentCompleted Methods와 Navigating을 전달하여 사용 방법에 대한 전체 그림을 제공합니다.
private void webBrowser_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
if (Program.BrowsingSystem.BrowserLink.ReadyState == WebBrowserReadyState.Complete)
{
lock (Program.BrowsingSystem.BrowserLocker)
{
Program.BrowsingSystem.ActualPosition = Program.BrowsingSystem.UpdatePosition(Program.BrowsingSystem.Document);
Program.BrowsingSystem.CheckContentAvailability();
Program.BrowsingSystem.IsBusy = false;
}
}
}
private void webBrowser_Navigating(object sender, WebBrowserNavigatingEventArgs e)
{
lock (Program.BrowsingSystem.BrowserLocker)
{
Program.BrowsingSystem.ActualPosition.PageName = OgamePages.OnChange;
Program.BrowsingSystem.IsBusy = true;
}
}
DoEvents()는 여기에 제시된 구현 뒤에 거짓말 세부 사항에 대해 지금 알고있는 경우 (이 S.에서 다른 사이트를 연결하는 문제가되지 않습니다 희망 뒤에 혼란을 알 수있는 모습 here을주십시오 과다).
Form 인스턴스에서 Navigate 메서드를 호출 할 때 호출을 Invoke 내부에 넣어야한다는 사실에 대한 마지막 작은 메모입니다.이 메서드는 작동해야하는 메서드가 있기 때문에 Invoke가 필요합니다. webBrowser (또는 심지어 refereed 변수로 범위에 포함)는 webBrowser 자체의 동일한 Thread에서 실행되어야합니다.
또한 WB가 일종의 Form 컨테이너의 하위 항목 인 경우 인스턴스 생성 위치의 스레드가 양식 작성과 동일해야하며 과도기 때문에 WB에서 작업해야하는 모든 방법 Form 스레드에서 호출해야합니다 (호출이 Form 네이티브 스레드에서 호출을 재배치). 이것이 유용하다고 생각합니다. (방금 Application.DoEvents()에 대해 어떻게 생각하는지 알려주기 위해 내 모국어로 된 코드에 // VERIFY 주석을 남겼습니다.)
종류의 안부 알렉스
이 내가 autoResetEvent.Set()를 직접 호출 할 것을 제외하고 내가 대신 중간체를 사용하는 (autoResetEvent.Reset를 (계속 차단 해제되지 않습니다)), 무엇을 기본적으로 triggerFunction. 그러나이 코드는 작동하지 않습니다. (다시 말하지만 EventHandler가 초기 호출과 동일한 스레드에서 실행되므로 스레드가 무기한 차단되면 이벤트가 실행되지 않습니다.) – Chris
메인 페이지 스레드가 실행을 끝내지 못하게하는 데 문제가있는 것 같습니다. 스레드를 일시 중단하는 경우 페이지는 렌더링을 계속 유지해야합니다 (스레드가됩니다). 어쩌면 잘못된 함수 호출을 보여 줬을 까? 그러나 페이지가 렌더링을 완료했음을 보장하기 때문에 이벤트 트리거에 스레드를 해제하려는 경우 (적어도 서버에서 생각하는 것처럼) –
DocumentCompleted 이벤트 처리를보다 명확하게하기 위해 게시물을 편집했습니다. 분명히 스레드가 실행되는 방식에 문제가 있지만 분명히 알 수는 없습니다. – Chris