Hash

Entries tagged as ‘C# WinForms’

Winforms .NET: Docking problem with ToolStrip and StatusStrip

February 6, 2009 · 2 Comments

Today I created a C# Winform with a ToolStrip and a SplitContainer beneath it. I wanted the SplitContainer to fill all of the form’s area but should start just under the ToolStrip, just like what you see in a normal Windows Form. To cover all area on the form and resize the SplitContainer with Form resize action I set the Dock property to FILL and the ToolStrip’s Dock property to TOP. The result was a SplitContainer spanning the whole Form and a ToolStrip on top of it. No! I tried a couple of different Dock value combinations with these controls but every time the result was one of them hiding the other one. And if you don’t set the Dock property it won’t resize itself with the Form.  After a little research on the internet and trying with different options I figured it out. The solution was not with the Docking values combination, they were right at the very first instance. It is the “Z” order of your controls which matter. Either:

  • Right click on SplitContainer and select “Bring to Front”
  • Or call BringToFront() in the code

The ToolStrip has to be at the back but since its Dock is set to TOP it will always be shown. And since SplitContainer is now brought at the Front it can’t be hidden by the ToolStrip.

 

Categories: .NET
Tagged: , , , , , , , , , , ,

C#: Parsing DateTime with TimeZone

February 2, 2009 · 4 Comments

I was writing code to parse the RSS Feed XML files the other day and I was getting exceptions on the published date.  The was happening because of the special format which is not supported by .NET. The published dates had the format:

Mon, 02 February 2009, 16:52:10 AEST

The names of the time zones are not supported by .NET because they are not unique. Different time zones in the world can have the same abbreviation.

If you try to parse this string using Convert.ToDateTime method the following error is shown:

System.FormatException: The string was not recognized as a valid DateTime. There is an unknown word starting at index XYZ.

 

To handle this situation I have written this piece of code as a separate class called Utils. The array is a private member of the class.

private static string[][] TimeZones = new string[][] {
    new string[] {"ACDT", "+1030", "Australian Central Daylight"},
    new string[] {"ACST", "+0930", "Australian Central Standard"},
    new string[] {"ADT", "-0300", "(US) Atlantic Daylight"},
    new string[] {"AEDT", "+1100", "Australian East Daylight"},
    new string[] {"AEST", "+1000", "Australian East Standard"},
    new string[] {"AHDT", "-0900", ""},
    new string[] {"AHST", "-1000", ""},
    new string[] {"AST", "-0400", "(US) Atlantic Standard"},
    new string[] {"AT", "-0200", "Azores"},
    new string[] {"AWDT", "+0900", "Australian West Daylight"},
    new string[] {"AWST", "+0800", "Australian West Standard"},
    new string[] {"BAT", "+0300", "Bhagdad"},
    new string[] {"BDST", "+0200", "British Double Summer"},
    new string[] {"BET", "-1100", "Bering Standard"},
    new string[] {"BST", "-0300", "Brazil Standard"},
    new string[] {"BT", "+0300", "Baghdad"},
    new string[] {"BZT2", "-0300", "Brazil Zone 2"},
    new string[] {"CADT", "+1030", "Central Australian Daylight"},
    new string[] {"CAST", "+0930", "Central Australian Standard"},
    new string[] {"CAT", "-1000", "Central Alaska"},
    new string[] {"CCT", "+0800", "China Coast"},
    new string[] {"CDT", "-0500", "(US) Central Daylight"},
    new string[] {"CED", "+0200", "Central European Daylight"},
    new string[] {"CET", "+0100", "Central European"},
    new string[] {"CST", "-0600", "(US) Central Standard"},
    new string[] {"CENTRAL", "-0600", "(US) Central Standard"},
    new string[] {"EAST", "+1000", "Eastern Australian Standard"},
    new string[] {"EDT", "-0400", "(US) Eastern Daylight"},
    new string[] {"EED", "+0300", "Eastern European Daylight"},
    new string[] {"EET", "+0200", "Eastern Europe"},
    new string[] {"EEST", "+0300", "Eastern Europe Summer"},
    new string[] {"EST", "-0500", "(US) Eastern Standard"},
    new string[] {"EASTERN", "-0500", "(US) Eastern Standard"},
    new string[] {"FST", "+0200", "French Summer"},
    new string[] {"FWT", "+0100", "French Winter"},
    new string[] {"GMT", "-0000", "Greenwich Mean"},
    new string[] {"GST", "+1000", "Guam Standard"},
    new string[] {"HDT", "-0900", "Hawaii Daylight"},
    new string[] {"HST", "-1000", "Hawaii Standard"},
    new string[] {"IDLE", "+1200", "Internation Date Line East"},
    new string[] {"IDLW", "-1200", "Internation Date Line West"},
    new string[] {"IST", "+0530", "Indian Standard"},
    new string[] {"IT", "+0330", "Iran"},
    new string[] {"JST", "+0900", "Japan Standard"},
    new string[] {"JT", "+0700", "Java"},
    new string[] {"MDT", "-0600", "(US) Mountain Daylight"},
    new string[] {"MED", "+0200", "Middle European Daylight"},
    new string[] {"MET", "+0100", "Middle European"},
    new string[] {"MEST", "+0200", "Middle European Summer"},
    new string[] {"MEWT", "+0100", "Middle European Winter"},
    new string[] {"MST", "-0700", "(US) Mountain Standard"},
    new string[] {"MOUNTAIN", "-0700", "(US) Mountain Standard"},
    new string[] {"MT", "+0800", "Moluccas"},
    new string[] {"NDT", "-0230", "Newfoundland Daylight"},
    new string[] {"NFT", "-0330", "Newfoundland"},
    new string[] {"NT", "-1100", "Nome"},
    new string[] {"NST", "+0630", "North Sumatra"},
    new string[] {"NZ", "+1100", "New Zealand "},
    new string[] {"NZST", "+1200", "New Zealand Standard"},
    new string[] {"NZDT", "+1300", "New Zealand Daylight "},
    new string[] {"NZT", "+1200", "New Zealand"},
    new string[] {"PDT", "-0700", "(US) Pacific Daylight"},
    new string[] {"PST", "-0800", "(US) Pacific Standard"},
    new string[] {"PACIFIC", "-0800", "(US) Pacific Standard"},
    new string[] {"ROK", "+0900", "Republic of Korea"},
    new string[] {"SAD", "+1000", "South Australia Daylight"},
    new string[] {"SAST", "+0900", "South Australia Standard"},
    new string[] {"SAT", "+0900", "South Australia Standard"},
    new string[] {"SDT", "+1000", "South Australia Daylight"},
    new string[] {"SST", "+0200", "Swedish Summer"},
    new string[] {"SWT", "+0100", "Swedish Winter"},
    new string[] {"USZ3", "+0400", "USSR Zone 3"},
    new string[] {"USZ4", "+0500", "USSR Zone 4"},
    new string[] {"USZ5", "+0600", "USSR Zone 5"},
    new string[] {"USZ6", "+0700", "USSR Zone 6"},
    new string[] {"UT", "-0000", "Universal Coordinated"},
    new string[] {"UTC", "-0000", "Universal Coordinated"},
    new string[] {"UZ10", "+1100", "USSR Zone 10"},
    new string[] {"WAT", "-0100", "West Africa"},
    new string[] {"WET", "-0000", "West European"},
    new string[] {"WST", "+0800", "West Australian Standard"},
    new string[] {"YDT", "-0800", "Yukon Daylight"},
    new string[] {"YST", "-0900", "Yukon Standard"},
    new string[] {"ZP4", "+0400", "USSR Zone 3"},
    new string[] {"ZP5", "+0500", "USSR Zone 4"},
    new string[] {"ZP6", "+0600", "USSR Zone 5"}
};

 

Then there is a static initializer of the class which creates a Hashtable for quick search.

private static Hashtable ZoneTable;

static Utils()
{
    ZoneTable = new Hashtable(50);

    foreach(string[] TimeZone in TimeZones)
    {
        ZoneTable.Add(TimeZone[0], TimeZone[1]);
    }
}

The actual conversion method is quite simple. First, try to parse the string without any change. This step can be skipped actually because all dates from an RSS Feed XML will contain the time zone name so this might be an overhead. If the parsing fails we replace the time zone name with the the actual offset.

public static DateTime ConvertWithTimezone(string StrDate)
{
    DateTime ConvertedDate;

    try
    {
        ConvertedDate = Convert.ToDateTime(StrDate);
        // just a plain date
        return ConvertedDate;
    }
    catch (FormatException fex)
    {
        // try finding a timezone in the date
        int TZstart = StrDate.LastIndexOf(" ");

        if (TZstart != -1)
        {
            string TZstr = StrDate.Substring(TZstart+1); // +1 to avoid the space character
            string TZvalue = ZoneTable[TZstr] as string;

            // its a timezone problem ...
            if (TZvalue != null)
            {
                // replace timezone name with actual hours (AEST = +1000)
                string NewDateStr = StrDate.Replace(TZstr, TZvalue);

                try
                {
                    ConvertedDate = Convert.ToDateTime(NewDateStr);

                    // success this time
                    return ConvertedDate;
                }
                catch (FormatException innerfex)
                {
                    // something else wrong, we dont know what to do
                    throw innerfex;
                }
            }
        }

        throw fex;
    }
}

Here we are. This is just like a wrapper on Convert.ToDateTime which modifies the date string before parsing it.

And have you noticed that the array of time zones is not complete. There are other time zones as well but I am using just the famous ones. The list of date times was taken from http://bytes.com/groups/net-c/214648-how-do-i-parse-date-w-time-zone.

Categories: .NET
Tagged: , , , , , , , , , ,

C#: Disallow multiple instances of your application. The Mutex way.

February 2, 2009 · 3 Comments

Previously I used the Process class to find out if a process with the same name is already running. Here is the link.

But that method had a problem. The code could easily be dodged by renaming the assembly. The Process class would give a different name the next time and a new instance will be started.

Now I have come up with the mutex which is much safer. Every time the application is started we check for a certain mutex. If the mutex exists we error out. Otherwise we go ahead, create that special mutex for our successors and run the application. Dont forget to release that mutex when application is about to exit.

try
{
    SingleInstanceMutex = Mutex.OpenExisting("TickerMutex0");
    Process.GetCurrentProcess().Kill();
}
catch (Exception ex)
{
    SingleInstanceMutex = new Mutex(false, "TickerMutex0");
}

If the OpenExisting method fails to open it will throw an exception which is fine. We create the mutex in this case and go on. And if a valid mutex is found, we simply close. The SingleInstanceMutex is a private member of the class of System.Threading.Mutex type. The Mutex is released when application is closed so we need to catch the Application_Exit event.

Application.ApplicationExit += new EventHandler(Application_ApplicationExit);

The body of Application_ApplicationExit function is:

void Application_ApplicationExit(object sender, EventArgs e)
{
    try
    {
        SingleInstanceMutex.ReleaseMutex();
    }
    catch (Exception ex)
    {
        MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
    }
}

 

 

 

I am using the Process.Kill method here because there is some special code in Application_Exit event which I dont want to run everytime.

Categories: .NET
Tagged: , , , , , , , , ,

C#: Check if a Form is already opened

January 28, 2009 · 8 Comments

During WinForms programming you might (chances are that you SHALL) come across a situation where you do not want to open a form multiple times on an event.  A common practice in the event handler function is:

UserForm UForm = new UserForm();
UForm.Show();

This will open your form, fine! But what if the event happens again and the previously opened UserForm has not been closed yet? A new UserForm will be opened and this will go on if the user loves that event  ^o :|

The prevention strategy is to check whether the form is already opened or not.

public static Form IsFormAlreadyOpen(Type FormType)
{
   foreach (Form OpenForm in Application.OpenForms)
   {
      if (OpenForm.GetType() == FormType)
         return OpenForm;
   }

   return null;
}

This little function will help in determining if a particular form is already opened or not.  You can open it or focus it later.

UserForm UForm = null;
if ((UForm = IsFormAlreadyOpen(typeof(UserForm)) == null)
{
    UForm = new UserForm();
    UForm.Show();
}
else
{
    UForm.DoWhatever(); // may be UForm.Select();
}

This works perfect for me. I don’t like that loop though.

Categories: .NET
Tagged: , , , , , ,