Web Browser in C#

*** Update ***

There is a newer version of the Browser with some more bug fixes done. Also, new video clip of the code available here.

Introduction

My second article will cover quite bit stuff. As I am learning C#, pretty fast I might add, things are so far so good. I hope you will find my code here useful and apply to your own with some modifications. After all, while you modify other peoples codes, you'll learn more and come up with your own ways to solve problems (so I believe).

This program called "WebPlus-V01". I know, there are many web browsers out there with all the bells-n-whistles but I added of a few new things that I haven't seen before... I'll get into C# code as much as I can here, also tell you most of the functionalities of the program. Please feel free to upload and play around with the code. I am very excited to see what else you guys would do (if you chose to enhance it)


Here are the most of the features,
  • Alarm timer: Have you ever had a problem browsing on the Internet and not knowing how long you were on, and forget about an important meeting or something. Well, no more. Use my browser, you can set its timer up to 2 hours to remind yourself that important meeting and not worry about the passing time while reading your favorite blogs :)
  • Blackout: I always annoyed by some people looking over my shoulder what I am doing or where I am going on the website. So, If you want to keep those annoying eyes out of your site, just blackout your page with its address bar, turn around and say "get the hell out of my back" without closing your browser at all... unless if that's your boss, then I have nothing to say, you deserve whatever he or she tells you :P
  • Notepad for your favorite websites: Each bookmark can also holds notes. It's there as an option. You always can make yourself notes if you see something interesting
  • Conversion tool: Next time when you are browsing some place and wonder how far 45 Km is, use the tool provided with the browser.
  • Bookmark folders: You can always create yourself separate bookmark folders and show only selected favorites on your list. No more clicking through the trees, just click and click ;)
Enjoy :)

Background

My very first article subject was a small program called "Code Database". I am using it for myself to keep my code snippets. Nothing fancy, I only want single thing from the program, which does it pretty good. I used XML file as my database because of the problems I had with MS Jet engine. I also mentioned that I tried SQL Express for that program, but decided go with the XML anyways. This time I am using SQL Express database. Everything in this code dynamic, nothing bounded to the database. It's an old habit of mine that I don't like to automate things by tying up them each other using bounding tools. Rather, I like to do them all myself. Reason? because that way I have more control over things and if something snaps, code will go one side, database to the other without tearing each other apart.

Using the code

There are two forms and one custom class for this program. The class file file contains two classes in it. They are not inheritance of each other, separate classes and duties. I do some stuff on my methods sometimes to make things more compact. Such as using multi-functional constructor :)
  • Form1 (Main form)
  • Form Settings
  • work.cs (Contains ETWork class and DBConn classes. As you will see in the code, ETWork class does two separate things depending on the parameters passed)
    SQL Express DB contains three tables,
  • Folder
  • Settings
  • UrlPath
Folders: Keeps the folder names for bookmarks.

Settings: Keeps the browser options and other goodies

UrlPath: Keeps the bookmarks with their extra information (Which one of the cool things I implemented)

Let's start with something I am dying to share. Indentation of my codes. Yes, it's not the center piece of the article, although this something I want to share first.

Following code samples are identical. I use the one looks like more compact. This way my line count gets much smaller and doesn't hurt my eyes looking at curly-brackets.

try {Conn1.Open();
    MyCommand.ExecuteNonQuery();
    Conn1.Close(); }

catch
(Exception exc) {
    throw exc; }

finally
{
    Conn1.Close(); }

-----------------------------------

try {
    Conn1.Open();
    MyCommand.ExecuteNonQuery();
    Conn1.Close();
}

catch
(Exception exc)
{
    throw exc;
}

finally

{

    Conn1.Close();
}

I don't recommend everyone using it... comes with practice and self-discipline. Even though VS indents the code for me, when I have time, I change them (it's a good exercise for me to go through the code again and again)

That's out of the way, I would like to share some codes with you. Again, I won't put the whole thing here, you can always download and take a look at the full code yourself.

Following code for the Search Engines I used on my web browser. You can see how "switch" was used, with multiple selection for one solutions, and "ToLower" property of the text class. "ToLower" is same as "LCase" in VB which makes every character in the text lowercase.

switch (clsDB.SEARCH_ENGINE)
{

    case
"Yahoo":
        CurrentSearchEngine = "search." + clsDB.SEARCH_ENGINE.ToLower() + ".com//search?p=";
        break;
    case "Google":
    case "Search":
    case "Bing":
        CurrentSearchEngine = "www." + clsDB.SEARCH_ENGINE.ToLower() + ".com//search?q=";
        break;
    case "Lycos":
        CurrentSearchEngine = "search." + clsDB.SEARCH_ENGINE.ToLower() + ".com/?tab=web&query=";
        break;

}

C# won't let you use numbers as starting characters for your variables. So, instead I used underscores. Which actually looked better if I did start with numbers ;)

private void ClearAlarmCheckBoxes()
{
    _5min.Checked = false;
    _15min.Checked = false;
    _30min.Checked = false;
    _1hr.Checked = false;
    _1nHalfHr.Checked = false;
    _2hr.Checked = false;

}

Here is a sample of formatting some numbers that used in my code to format results of the conversion utility  "lblResult.Text = String.Format("{0:0,0.0}".
The conversion utility I created converts three systems. Kilo to Lb, C to F, and Km to Mile (and vice-versa)

switch (XSelection)
{
    case 1:
        ResY = ConversionNumber * 1609.344;
        break;
    case 2:
        ResY = ConversionNumber * 0.621;
        break;
    case 3:
        ResY = (5.00 / 9.00) * (ConversionNumber - 32);
        break;
    case 4:
        ResY = (9.00 / 5.00) * ConversionNumber + 32;
        break;
    case 5:
        ResY = ConversionNumber * 0.4535;
        break;
    case 6:
        ResY = ConversionNumber * 2.2046;
        break;
}

_ConvertedNumber = ResY; // Set the result

You see "_ConvertedNumber" also has underscore. Because this code located in a class, and that is a field. I use all my fields (I try to) starting with underscores to identify them better.

Case 1 and 2 is for length, 3 and 4 is for temperature and last two are for weight.

You will see a lots of comments like this one "clsDB = new DBConn(); // Create an instance of 'DBConn' class" which I wanted to emphasize how important is to understand the "concept" of the OOP programming. It's all about creating a usable copy (object) of the code you create.

I just don't want to repeat previous article and duplicate codes in the next one. So, even though there are other stuff that I used which could be very useful for you to learn tiny stuff can be found in this code as well as in previous articles.

Now, let's see the DB stuff.

There are four major functionality that I need to implement to my DB codes. Very first one is to enter new data "INSERT INTO table (...) VALUES(..)". Second one it modifying the data "UPDATE table SET field = value, ...", delete data "DELETE FROM table.." and the last one is to request for data "SELECT fields FROM table"

Although those are the main four things, there are other stuff that you will use to do more work. Such as, Joining tables and/or databases in one string. It's not easy but after you create a few codes, it gets easier. I didn't have to use "JOIN" in this code but I have used them many times in the past. Queries looks the same in most DB cases with some minor adjustments from one to another. (Of course there are more stuff to this ;)

Entering new data,

public void NewBookmark(int FolderID, string BookMarkName, string BookMarkUrl)
{
    // Create new bookmark
    CommaCheck(BookMarkName); // Cleanup commas
    Conn1 = new SqlConnection(connStr); // Create an instance of 'SqlConnection' class
    SqlCommand MyCommand = Conn1.CreateCommand(); // Create an instance of 'SqlCommand' class
    MyCommand.CommandText = "INSERT INTO UrlPath (FolderID, CustomName, FullUrlPath) VALUES ("
                         + FolderID + ", '" + BookMarkName + "', '" + BookMarkUrl + "')";
    try {
        Conn1.Open(); MyCommand.ExecuteNonQuery();
        Conn1.Close(); }
    catch (Exception exc) {
        throw exc; }
    finally {
        Conn1.Close(); }

}

Modifying data,

public void SaveSettings()
{
    // Save settings when click 'Save/Exit' button
    // on the Settings form
    Conn1 = new SqlConnection(connStr); // Create an instance of 'SqlConnection' class
    SqlCommand MyCommand = Conn1.CreateCommand(); // Create an instance of 'SqlCommand' class
    MyCommand.CommandText = "UPDATE settings SET SearchEngine = '" +
        _SearchEngine + "', StartMax = " + BoolBitConversion(_StartMax) + ", ShowToolTips = " +
        BoolBitConversion(_ShowToolTips) + ", RememberRefresh = " + BoolBitConversion(_RememberRefresh) +
        ", SaveHistory = " + BoolBitConversion(_SaveHistory);
    try {
        Conn1.Open(); MyCommand.ExecuteNonQuery();
        Conn1.Close(); }
    catch (Exception exc) {
        throw exc; }
    finally {
        Conn1.Close(); }

}

Deleting data,

public void DeleteSelectedBookmark(string BookMarkID)
{
    // Delete bookmark
    int ConvertID;
    ConvertID = Convert.ToInt32(BookMarkID);
    Conn1 = new SqlConnection(connStr); // Create an instance of 'SqlConnection' class
    SqlCommand MyCommand = Conn1.CreateCommand(); // Create an instance of 'SqlCommand' class
    MyCommand.CommandText = "DELETE FROM UrlPath WHERE ID = " + ConvertID;
    try {
        Conn1.Open(); MyCommand.ExecuteNonQuery();
        Conn1.Close(); }
    catch (Exception exc) {
        throw exc; }
    finally {
        Conn1.Close(); }

}

Requesting data,

public List<string> FillBookMarks(int SelectedFolderID)
{
    // Fill the bookmark list from selected boomark folder
    List<string> BookMarkList = new List<string>(); // Create an instance of 'List<T>' array class
    Conn1 = new SqlConnection(connStr);
    SqlCommand MyCommand = Conn1.CreateCommand();
    char Splitchr = (char)8;
    try { Conn1.Open();
        MyCommand.CommandText = "SELECT ID, CustomName, FullUrlPath FROM UrlPath WHERE FolderID = " +
                                                SelectedFolderID; // set query
        SqlDataReader Rs1 = MyCommand.ExecuteReader();
        while (Rs1.Read()) {
            BookMarkList.Add(Convert.ToString(Rs1.GetInt32(0)) +
                                    Splitchr + Rs1.GetString(1).Trim() + Splitchr + Rs1.GetString(2).Trim()); } }
    catch (Exception exc) {
        throw exc; }
    finally {
        Conn1.Close(); Conn1.Dispose(); Conn1 = null; MyCommand.Dispose(); MyCommand = null; }
    return BookMarkList;

}

I researched and found this code. There is no way I would know if I didn't Google it. These are the main things that I admire the most when I find solutions for. What's from here is to explore my other options for my other needs with it. This code deletes the history file for Internet Explorer.

public void DeleteIEHistory()
{

    string
[] theFiles = Directory.GetFiles(Environment.GetFolderPath(Environment.SpecialFolder.History),
                                                                            "*", SearchOption.AllDirectories);
    foreach (string DelThis in theFiles)
    {
        try { File.Delete(DelThis); }
        catch
        {
            // Do Nothing
        }
    }

}

I have used two timer controls for this program. One to countdown the alarm, and other to refresh the webpage. Tere are some other options to create my own classes and use "timer" .NET class instead of using controls, but I got lazy. Here is one of them

#region Alarm / Countdaown stuff //
private
void tmrCountDown_Tick(object sender, EventArgs e) // Alarm timer count down
{
    // This is the code counts the time until is up and flashes the frame
    // after that until it is stopped by the 'button' or 'cancel menu item'.
    if (TickCount > 0) {
        TickCount -= 1; }
    else {
        btnStopAlarm.Visible = true;
        if (FlashingRed == true) {
            FlashingRed = false;
            pnlColor.BackColor = Color.White; }
        else {
            FlashingRed = true;
            pnlColor.BackColor = Color.Red; }
    }
}


private
void btnStopAlarm_Click(object sender, EventArgs e)
{
    StopCancelAlarm(); // Stop 'flashing frame' and stop the timer
}

private void StartCountDown(int AddingTime)
{
    // Set some variables before start the timer
    ClearAlarmCheckBoxes();
    TickCount = AddingTime;
    btnStopAlarm.Visible = false;
    pnlColor.BackColor = Color.Green;
    tmrCountDown.Start();
}

............... 

private void StopCancelAlarm()
{
    // Stop the timer and set the
    // variables back to defaults
    ClearAlarmCheckBoxes();
    pnlColor.BackColor = Color.LightGray;
    btnStopAlarm.Visible = false;
    FlashingRed = true;
    tmrCountDown.Stop();
    tmrCountDown.Dispose();
}

#endregion

You see, I also use my own separators to follow my code easier. "#region" also is helping me a lot if I need to hide some codes during painful debugging. I know I did duplicate my tips from the previous article now, but I felt it's important for you to know "#region" is available for you now :)

Points of Interest

This code also is for C# beginners. I do research a lot to learn a lot. As much as you can use any code I post here. I also would like to see your options as well. If you are interested in doing some enhancements, I would owe you a lot for teaching me how to fish better ;)

(By the way, my code has some stuff missing, such as error handlers. I will fix all the handlers later on. Although I am using exceptions, I am not taking care of them at the end-code. There are some other stuff that I probably didn't mention here such as how to delete bookmarks, where to click for the blackouts... So, they might be good study material for you as well :)