Hi,
I need help on Webbrowser Documentcompleted event which is fired only when i click once on my main form toolbar.
I think it's a thread problem but i don't know how to solve it!
Please help!
I hope it's related to this discussion.
I had tried to use thead to wait for event documentcompleted but may main form continue its code before browsing was totally completed...
Here is the environnement:
I have one main form which contains a WebBrowser control named myBrowser.
In this main form, i call Class BrowserGE like follows to read all html pages and cascaded browse from page to page.
public frmMain()
{
InitializeComponent();
//retrieve Last Game imported through stored Proc
GamesDatabaseDataSetTableAdapters.QueriesTableAdapter lastGame = new StatsBG.GamesDatabaseDataSetTableAdapters.QueriesTableAdapter();
//Instantiate new BrowserGE
myBrowser = new BrowserGE(mainWebBrowser, (int)lastGame.LastGameImported());
}
private void btnBrowser_Click(object sender, EventArgs e)
{
//LogIn and read newgames to be imported
Games newGames;
newGames = myBrowser.ReadNewGames();
...
...
}
My class used to browse is this one:
class BrowserGE
{
public Games games; // games to be readden
private WebBrowser myWebBrowser;
IFormatProvider culture = new CultureInfo("en-US", true); //to read good date format
private HtmlDocument doc; // contains innerhtml of current page
private int _numPage; // current numver page to navigate
private int _lastGameImported; // last game imported
private string _currentUrl; //current url
ReadState continueBrowse = ReadState.NotInitialized; // state of total browsing
public enum ReadState
{
NotInitialized,
ReadingError,
Finished,
ContinueOnNextPage
}
/// <summary>
/// Constructor
/// </summary>
private BrowserGE()
{
_numPage = 0;
myWebBrowser = new WebBrowser();
games = new Games();
}
/// <summary>
/// Public Constructor
/// </summary>
/// <param name="mainWebBrowser">WebBrowser control linked to (for navigation)</param>
/// <param name="lastGameImported">last game imported to avoid import same games</param>
public BrowserGE(WebBrowser mainWebBrowser, int lastGameImported)
: this()
{
myWebBrowser = mainWebBrowser;
myWebBrowser.DocumentCompleted += new System.Windows.Forms.WebBrowserDocumentCompletedEventHandler(myWebBrowser_DocumentCompleted);
_lastGameImported = lastGameImported;
}
/// <summary>
/// Read html games (synchronized method to wait end of this method before continue on caller method)
/// </summary>
/// <returns>games added</returns>
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.Synchronized)]
public Games ReadNewGames()
{
Browse();
return games;
}
/// <summary>
/// Main cascaded Browse in all pages: LogIn, page 1, page2,etc
/// </summary>
private void Browse()
{
if (continueBrowse != ReadState.NotInitialized)
{
_numPage = -1;
NextPage();
continueBrowse = ReadState.ContinueOnNextPage;
}
while (continueBrowse != ReadState.Finished & continueBrowse != ReadState.ReadingError)
{
//myWebBrowser.Focus();
Application.DoEvents();
// Thread.Sleep(100);
if (myWebBrowser.ReadyState == WebBrowserReadyState.Uninitialized & !myWebBrowser.IsBusy)
{
//Log in page
myWebBrowser.Navigate(Settings.Default.UrlGELogIn);
Application.DoEvents();
}
//Wait for document completed event to fill doc with innerhtml
else if (doc != null & myWebBrowser.ReadyState == WebBrowserReadyState.Complete & !myWebBrowser.IsBusy)
{
if (_currentUrl == Settings.Default.UrlGELogIn)
{
LogInUserPassword();
}
else if (_currentUrl == Settings.Default.UrlMenu)
{
myWebBrowser.Navigate(Settings.Default.UrlGEGamesHistory);
}
else if (_currentUrl == Settings.Default.UrlGEGamesHistory)
{
//Find first form never submitted
//Submit firt form first time only
if (doc.Forms.Count > 0)
{
if (doc.GetElementById(Settings.Default.FieldNameGameHistoryDataGrid) == null)
{
doc.Forms[doc.Forms.Count - 1].InvokeMember("submit");
}
else
{
continueBrowse = ReadPage();
if (continueBrowse == ReadState.ContinueOnNextPage)
{
NextPage();
}
else if (continueBrowse == ReadState.Finished)
{
if (DialogResult.Yes == MessageBox.Show("Do you want to insert these " + 12 + " new games ?", "Confirm update", MessageBoxButtons.YesNo))
{
//GamesDatabaseDataSetTableAdapters.GamesTableAdapter ga = new StatsBG.GamesDatabaseDataSetTableAdapters.GamesTableAdapter();
//ga.Update(GamesDatabaseDataSet.GamesDataTable());
}
}
else if (continueBrowse == ReadState.ReadingError)
{
MessageBox.Show("Html Reading error");
}
//Settings.Default.UrlGEGamesHistory, Settings.Default.UrlNextGameStart, Settings.Default.UrlNextGameEnd);
}
}
else
{
throw new Exception("Unable to find form of html data grid!!!");
}
}
else
{
throw new Exception("Where goes my browser?\n" + _currentUrl);
}
}
}
}
/// <summary>
/// Navigate to first LogIn Page
/// </summary>
/// <param name="loginUrl">url to vaigate</param>
/// <param name="user">user name</param>
/// <param name="pwd">password</param>
private void LogIn(string loginUrl, string user, string pwd)
{
try
{
myWebBrowser.Navigate(Settings.Default.UrlGELogIn);
}
catch (System.InvalidOperationException e)
{
MessageBox.Show("Error to log in" + e.Message, "LogIn");
//throw;
}
catch (Exception e)
{
MessageBox.Show("Error to log in" + e.Message, "LogIn");
//throw;
}
}
/// <summary>
/// Navigate to next page
/// </summary>
private void NextPage()
{
//Firt form already submitted, find html data grid
_numPage++;
myWebBrowser.Navigate(Settings.Default.UrlNextGameStart + _numPage + Settings.Default.UrlNextGameEnd);
}
/// <summary>
/// Read current html page
/// </summary>
/// <returns></returns>
private ReadState ReadPage()
{
// List games returned
HtmlElement htmlTable;
HtmlElementCollection htmlRows;
HtmlElement oneHtmlRow;
HtmlElementCollection HtmlCells;
int numRow = 0;
int currentGame = int.MaxValue;
DateTime currentDate;
string currentOpponent;
string currentGameType;
byte currentDiceCube;
float currentWin;
float currentLoose;
ReadState toBeContinue = ReadState.ContinueOnNextPage;
_numPage = 0;
if (doc != null)
{
htmlTable = doc.GetElementById(Settings.Default.FieldNameGameHistoryDataGrid);
if (htmlTable != null)
{
numRow = 0;
htmlRows = htmlTable.GetElementsByTagName(Settings.Default.HtmlGamesRow);
if (htmlRows.Count > 0)
{
oneHtmlRow = htmlRows[numRow];
//Browse until lastGameImported
#region Browse until lastGameImported
while ((oneHtmlRow != null) & (toBeContinue == ReadState.ContinueOnNextPage))
{
if (numRow > 0)//Cancel First row of headers
{
HtmlCells = oneHtmlRow.GetElementsByTagName(Settings.Default.HtmlGamesColumn);
if (HtmlCells != null & HtmlCells.Count > 6)
{
//SessionID
if (currentGame==47047186)
{
MessageBox.Show(currentGame.ToString());
}
currentGame = int.Parse(HtmlCells[0].InnerText);
HtmlCells[0].ScrollIntoView(true);
//MessageBox.Show("CurrentGame=" + currentGame + "(must be > " + _lastGameImported + ") ==> " + (currentGame - _lastGameImported).ToString());
if (currentGame > _lastGameImported)
{
#region Write html values in games object
try
{
currentDate = DateTime.Parse(HtmlCells[1].InnerText, culture, System.Globalization.DateTimeStyles.None);
currentOpponent = HtmlCells[2].InnerText;
currentGameType = HtmlCells[3].InnerText;
byte.TryParse(HtmlCells[4].InnerText, out currentDiceCube);
float.TryParse(HtmlCells[5].InnerText, out currentWin);
float.TryParse(HtmlCells[6].InnerText, out currentLoose);
if (null == games.Add(currentGame, currentDate, currentOpponent, currentGameType, currentDiceCube, currentWin, currentLoose))
{
toBeContinue = ReadState.ReadingError;
throw new Exception("Error to insert game " + currentGame);
}
}
catch (Exception e)
{
throw e;
}
#endregion
if (numRow+1 < htmlRows.Count & numRow < Settings.Default.HtmlNumberOfGamesByPage)
{
oneHtmlRow = htmlRows[++numRow];
}
else
{
oneHtmlRow = null;
toBeContinue = ReadState.ContinueOnNextPage;
}
}
else
{
oneHtmlRow = null;
toBeContinue = ReadState.Finished;
}
}
else
{
toBeContinue = ReadState.Finished;
}
}
else
{
oneHtmlRow = htmlRows[++numRow];
}
}
#endregion
}
else
{
toBeContinue = ReadState.ReadingError;
}
}
else
{
toBeContinue = ReadState.ReadingError;
}
}
else
{
toBeContinue = ReadState.ReadingError;
}
return (toBeContinue);
}
/// <summary>
/// Document completed event to get html content page when completly loaded
/// </summary>
/// <param name="sender">Sender</param>
/// <param name="e">Exception</param>
private void myWebBrowser_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
if (myWebBrowser.ReadyState == WebBrowserReadyState.Complete)
{
doc = myWebBrowser.Document;
_currentUrl = ((WebBrowser)sender).Url.AbsoluteUri;
}
}
/// <summary>
/// To fill user and password in login page
/// </summary>
private void LogInUserPassword()
{
if (myWebBrowser.ReadyState == WebBrowserReadyState.Complete)
{
HtmlElement elt;
//Set user name if empty
elt = doc.GetElementById(Settings.Default.FieldnameLogInUser);
if (elt.GetAttribute("value") == "")
{
elt.SetAttribute("value", Settings.Default.FieldnameLogInUserValue);
}
//Set Pwd if empty
elt = doc.GetElementById(Settings.Default.FieldnameLogInPwd);
if (elt.GetAttribute("value") == "")
{
elt.SetAttribute("value", Settings.Default.FieldnameLogInPwdValue);
//Submit first form
doc.Forms[0].InvokeMember("submit");
}
}
}
}