Thursday, March 28, 2013

Do the Right Thing in Behind the Splash Screen

Prerequisite : Microsoft Visual Studio, Microsoft SQL Server (Any version)

I have seen many novice developers/students using a splash screen in their applications to give a good impression to the user. They usually place a timer and inside the timer tick event update the progress bar value and the text of a label. When the cap value reached 100 they close the splash screen and prompt the Login screen (if you have). 

The real purpose of the Splash screen is clearly described in this Wikipedia article. 

This is how I've done it differently for a 3-layer application, where the presentation layer and the business logic layer are connected through a web/WCF service. If you are unfamiliar with the web services or WCF, consider the serviceClient class as a regular class that calls some functions in the business logic layer.

Steps :
1. Add a new Windows Form (Splash.cs) to the project.
2. Set the following Properties of the Splash screen to the given values.
    -   ControlBox : false
    -   FormBoarderStyle : none
    -   ShowIcon : false
    -   ShowInTaskBar : false
    -   StartPosition : CenterScreen
    -   Size : 450,250 (Change according to the size of your image, If you have prepared any)

   If you provide a background image, set these values
    -   BackroundImage : brows and set your image
    -   BackgroundImageLayout : Zoom
    -   Transparency Key : set the colour that should be displayed as transparent.
3. Place some labels add a progress bar to the Splash form, and give whatever text is appropriate.
    Set the label BackColor to transparent, otherwise, labels will be displayed with a gray colour.


 4. Define a boolean variable inside the Splash.cs as follows. 
 public bool IsValidationCompleted  
 {  
     get;  
     private set;  
 } 

 5. Now set splash screen as the first screen by placing the following code in the Program.cs file.
 Application.EnableVisualStyles();  
   Application.SetCompatibleTextRenderingDefault(false);  
      //---- Added Code ----------------  
   Splash splash = new Splash();  
   Application.Run(splash);  

6. Clear the text of the status message and initialize IsValidationCompleted to false inside the Splash screen window constructor,
  public Splash()  
  {  
     InitializeComponent();  
     IsValidationCompleted = false;  
     lbStatusMessage.Text = "";  
  }  

7. Add a new class named serviceClient and implement your initial validation logic, basic data download, or what ever process that should be executed before the main UI is shown to the user. For the demonstration purpose, I will create some dummy methods as follows.

 public bool PingToService()  
 {  
   try  
   {  
      /* Create a client object and call a method in the service   
       * and return the value. You may implement the Ping method in   
       * the web/wcf service as follows.  
       * public bool Ping()  
       * {  
       *  return true;  
       * }  
       */  
      //------ For the Demonstration Purpose ------------------------  
        System.Threading.Thread.Sleep(1000);  
        return true;  
        //-------------------------------------------------------------    
   }  
   catch   
   {  
      /* If you want to handle the exception exactly one   
       * at a time implement as follows   
       * try{ .... }  
       * catch (ServiceException ex)  
       * {}  
       * catch (XYZException ex)  
       * {}  
       * catch(Exception ex)  
       * {}  
      */  
      return false;  
   }  
 }

 public bool CheckDataBaseConnectivity()  
 {  
    //------ For the Demonstration Purpose ------------------------  
     System.Threading.Thread.Sleep(1000);  
     return true;  
    //-------------------------------------------------------------    
 }

 public bool DownloadSomeData()  
 {  
     //----- For the Demonstration Purpose ------------------------  
     System.Threading.Thread.Sleep(1000);  
     return true;  
     //------------------------------------------------------------    
 }   
  
8. Now implement a method called InitialValidation inside the Splash.cs file and call the validation methods implemented in the above step as follows
 private void InitialValidation()  
 {  
   try  
   {  
      // Invoke an UI update through a delegate  
       this.Invoke((MethodInvoker)delegate  
       {  
          lbStatusMessage.Text = " Connecting ....";  
          progressBar1.Value = 10;  
       });  
       ServiceClient oServiceClient = new ServiceClient();  
       if (oServiceClient.PingToService())  
       {  
          this.Invoke((MethodInvoker)delegate  
          {   
             lbStatusMessage.Text = "Service Connectivity is OK ....";  
             progressBar1.Value = 20;  
          });  
          if (oServiceClient.CheckDataBaseConnectivity())  
          {  
             this.Invoke((MethodInvoker)delegate  
             {  
                 lbStatusMessage.Text = "DB Connectivity is OK ...";  
                 progressBar1.Value = 50;  
             });  
          }   
          if (oServiceClient.DownloadSomeData())  
          {  
             this.Invoke((MethodInvoker)delegate  
             {  
                lbStatusMessage.Text = "Configuration has applied ....";  
                progressBar1.Value = 70;  
             });  
          }  
          this.Invoke((MethodInvoker)delegate  
          {  
              lbStatusMessage.Text = "Finalizing ....";  
              progressBar1.Value = 90;  
          });  
          //---------- For the Demonstration Purpose ------------------------  
          System.Threading.Thread.Sleep(1000);  
          //----------------------------------------------------------------  
         this.Invoke((MethodInvoker)delegate  
         {  
           lbStatusMessage.Text = "";  
           progressBar1.Value = 100;  
         });  
      }  
      IsValidationCompleted = true;  
      // Invoke UI update  
      this.Invoke((MethodInvoker)delegate  
      {  
         this.Dispose();  
      });  
    }  
    catch (Exception Ex)  
    {  
      MessageBox.Show(Ex.Message, "Stop", MessageBoxButtons.OK, MessageBoxIcon.Error);  
      IsValidationCompleted = false;  
      Application.Exit();  
     }
 }

Make sure you assign the correct value for the variable IsValidationCompleted at the end of this method.

9. Then go to the design view of the Splash screen window, and double-click on an empty area to generate the Load event. Place the following code inside the form load event.
 System.Threading.Thread thread = new System.Threading.Thread(  
                      () => InitialValidation());  
 thread.Start();  

10. Now, if you run your project, and must see the splash screen with an incrementally increasing progress bar. Once it reaches 100 splash screen will be closed and the focus to the Visual Studio, Now you can prompt the login screen, to do that place the following code inside the program.cs file and call your login screen 
 if (frmSplash.IsValidationCompleted)  
  {  
   //-------- Show the Login Screen -------------  
  }  



Tuesday, March 5, 2013

Think in Reverse (Class Diagrams) - Composition,Aggregation & Association

If you are looking for something simple to understand the difference between association, aggregation, and composition, Then this article will be useful to you.

There are three primary inter-object relationships: association, aggregation, and composition. Using the correct relationship is important for placing implicit restrictions on the visibility and propagation of changes to the related classes, matters which play a major role in reducing system complexity.

Association :
A person and a company are two individual entities, but a person can work in a company, and he is called an employee... So the employee has an existence in the outer world as a person. So even if the company perishes, but the person will not perish.

 public class Example {  
   public static void main(String[] args) {  
     Person p1 = new Person("Vishal");  
     Company abc = new Company(p1);  
   }  
 }  
 class Person{  
   String name;  
   public Person(String name) {  
     this.name = name;  
   }  
 }  
 class Company{  
   Person employee;  
   public Company(Person p1) {  
     employee = p1;  
   }  
 }  

Composition (Non-Shared Association):
 public Class Client  
 {  
   BankAccount acc = new BankAccount();  
   public void addMoneyToBankAccount(decimal amount)  
   {       
     acc.AddMoney(amount);  
   }  
   public decimal CheckBalance()  
   {  
     return acc.CheckAccountBalance();  
   }  
 }  

** Points to notice: Client class has defined the BankAccount attribute (acc) as a class variable and initialized at the point of declaration. If I simply say, BankAccount is a part-of Client.   If inheritance gives us 'is-a' and composition gives us 'part-of', we could argue that aggregation gives us a 'has-a' relationship.

Aggregation (Shared Association): 
 Class Client  
 {  
   BankAccount acc;  
   public Client(BankAccount p_acc)  
   {  
    acc=p_acc;  
   }  
   public decimal CheckBalance()  
   {  
     return acc.CheckAccountBalance();  
   }  
 }  

Within aggregation, the lifetime of the part is not managed by the whole. The client class is only keeping a reference for BankAccount class, but is not controlling its object lifetime.

Even after the client object is destroyed, BankAccount object used within can be assigned for another Client.

Office Development : How to make an Excel cell read only

*** Please note that this article describes how to lock an Excel cell from code in Excel Add-in/Template/ Workbook type Visual Studio projects. If you want to make an Excel cell read only from within your application, please check the comments.

In order to lock the cells for a given range, first set the Locked property for that range to true and then protect that particular sheet. This will lock the cells from being edited. The following sample code will lock the cell range from A1 to C3 from editing.
this.Application.Cells.Locked = false;
this.Application.get_Range("A1", "C3").Locked = true;
Excel.Worksheet Sheet1 = (Excel.Worksheet)this.Application.ActiveSheet;
Sheet1.Protect(missing, missing, missing, missing, missing, missing, missing 
        missing, missing, missing, missing, missing, missing, missing,                            missing, missing);

References :
http://social.msdn.microsoft.com/Forums/en/vsto/thread/f89fe6b3-68c0-4a98-9522-953cc5befb34
http://social.msdn.microsoft.com/Forums/en-US/vsto/thread/583f39a1-c3e2-4aaf-8c85-caacb6dbfa94