A guide to using Paneled Forms, Multi-Splash Screens, SQL Express, and many more in Windows Application Development By msalmank | 20 Sep 2005 Part of The SQL Zone. A quick hands-on application to guide you in using paneled forms, multi-splash screens, SQL Express, and many more.... Prize winner in Competition "VB.NET Aug 2005" Is your email address OK? You are signed up for our newsletters but your email address is either unconfirmed, or has not been reconfirmed in a long time. Please click here to have a confirmation email sent so we can confirm your email address and start sending you newsletters again. Alternatively, you can update your subscriptions. Download source files - 1.51 Mb Download demo project - 913 Kb Introduction After writing the article 'Using Paneled Forms in Windows Applications', I decided to spice up something in VS 2005 Beta 2. Though at first my intentions were to write a simple application exploring the How-to of Paneled Forms development in Beta 2, as I delved more and more into the studio, I found myself adding more and more stuff to the application. In the end, I ended up with a simple address book, using Paneled Forms in VB.NET with SQL Express as back-end. Paneled Forms I think I'll start with Paneled Forms first and explain the how-to of them in Visual Studio 2005. As explained in my previous article, "Using Paneled Forms in Windows Applications", we can use a single form with a panel control that can be used to load user controls. What does user controls offer? Everything, except having the ability to act as a form, i.e. a form is independent, but a user control is dependent. A user control is a Type, whereas a form is a Member of the Windows application. (Create a project, and delete any forms, try creating a user control as start-up, the following error is returned: 'UserControl1' is a type in 'TestApp' and cannot be used as an expression.) It is important to mention here that user controls have almost all the properties as a Form� for instance, we can add menus to each individual user control, set opacity, auto size the control, etc. Here I would like to request those of you who haven�t read the article 'Using Paneled Forms in Windows Applications' to read that article before proceeding further, as I won't be explaining the process in full detail. As in my previous application, this application has one Windows Form, 'myMainForm' and various user controls. This single form contains a Panel, 'myPanel', which is the Panel that will be used to populate user controls. As shown in Figure 1 the grayish rectangular area on the form is the Panel. In the Load event of this form I want to add a user control to the panel to be displayed. Here is the code for that: Collapse Dim tempObject As New ctrlMain Me.myPanel.Controls.Clear() Me.myPanel.Controls.Add(tempObject) I have included these lines in the myMainForm_Load(�,�) function. Thus, when the form is loaded, the application creates an object of the user control, ctrlMain (Figure 2), and adds it to myPanel by calling the Add method and passing in the object created. One might ask what is the significance of the second statement, i.e. myPanel.Controls.Clear(). It clears the panel, removing all the controls that it already had. Why do I call it here? No reason at all. Comment this line of code and the application functions in the same way as it did before. Though I do have a reason of including this in the code, and that is to make you familiar with the Clear method as I will be explaining later on how a common approach of using this statement results in errors while execution� Now, we want to transfer to another control, taking the example from our application, let�s say we click the button labeled 'Add New Entry', this calls for swapping our current control with ctrlAddNewEntry (Figure 3). Here are the three lines of code that is used to accomplish this task: Collapse Dim tempObject As New ctrlAddNewEntry Me.ParentForm.Controls.Item("myPanel").Controls.Add(tempObject) Me.ParentForm.Controls.Item("myPanel").Controls.RemoveAt(0) In the first line we create an object of the control ctrlAddNewEntry. In the next one we add that object to myPanel's controls. The tricky thing is that we are not functioning from our main form, i.e. myMainForm. We have to access our panel from within our current user control. To do this there are two methods. The first one is to access the main form using the Parent property. The other is to use the ParentForm property, as used above. I prefer the ParentForm property over the Parent property. It is far simpler, as the ParentForm property will access the Parent Form of the control, whereas the Parent property accesses the parent container of the control. Also note the major difference between Paneled Forms in VS 2003 and VS 2005, we are accessing the Panel by using its name, if you remember my previous article, we had to use the index of the item, from the designer generated code to access it, no names. This definitely is quite handy, as there�s no chance of getting the wrong index in this case!!! The third line of code removes the control at index 0, from the control collection of the panel. The control collection acts as a queue, thus following the FIFO rule, 'First in First out'. So, when we add a new control to our panel�s control collection, it gets stored at index 1. Upon removal of the control at index 0, the new control moves to index 0 from 1. Warning!!! In common practice, coders try to use myPanel.Controls.Clear() to clear the panel of any controls and then add the new control. Similarly some call myPanel.Controls.RemoveAt(0) before adding the new control to the panel. These both result in the following error: 'Object Reference not set to an instance of the object'. This is because the command clears the last item in the control collection, and it gets disposed of. Although the panel is accessible, accessing the control collection will result in an error. Now if we want to swap our user control again, we can use the same three lines of code, the only change being that we will be creating the object of the control we want to swap to. Multi-splash screens Now that we�ve covered the how-to of Paneled Forms in VS 2005, let�s get started on splash screens. Splash screens are often used to display information to a user while an application is loading. They are basically a Windows Form without any form border. Visual Basic provides a preconfigured splash screen form template that can be added to a Windows application project, and a splash screen property in the Project Designer that allows specifying a splash screen for a project. Creating a splash screen To create a splash screen simply add a Windows Form to the project. Open the form in designer mode, right click on it and open its properties. Scroll down to the Appearance properties of the form and set the FormBorderStyle property to none. Next, scroll down to Window Style properties, and set the ShowInTaskbar property to false. Now choose an image that you�d like to use as your splash screen and add it as the background image of the form. I usually add two labels to my splash screens and they are as follows: 1. Application Title This label will show the application title on the splash screen. We can set its value on the Load event of the splash screen. The best way to do this is to get the application title from the assembly information using: Collapse My.Application.Info.Title But there is a good chance that the application title is empty, unless we specify it beforehand. To take care of this, we can use the following check: Collapse My.Application.Info.Title <> "" If its true then use this value else we can get the file name of the application without the extension by calling the following method: Collapse System.IO.Path.GetFileNameWithoutExtension() Parameter: My.Application.Info.AssemblyName 2. Version Another thing a user might want to see on a splash screen is the version information. I am using the String.Format() function as specified in the default splash screen template. I will not explain this function here but will recommend using MSDN help on String.Format() for better understanding. The next thing to do is to have the splash screen show up before any other form in the application. The fastest and easiest way is to use the Project Designer�s splash screen property (Figure 4). But the problem with this is that it is hard to control how long the splash screen stays opened, when it loses focus, how it appears, and to add additional functionality to it. My splash screens I'll jump directly to the splash screen that I am using and how I am using it. The splash screen is shown in Figure 5 . As my application�s startup form is myMainForm, I have added the following code to its OnLoad event: Collapse 'Splash Screen Call � Version 0.02 mySplashScreen.ShowDialog() Confused!!! I know. First I was using the following syntax: Collapse 'Splash Screen Call � Version 0.01 Dim tempForm As New mySplashScreen tempForm.ShowDialog() Why did I change it? Why did I not create an object of mySplashScreen in the later version? I�ll answer these questions, but first I need to explain the functionality of the splash screen. For now consider that I am using the splash screen version 0.01. Let�s add the following text to mySplahScreen's onLoad event call. Collapse If My.Application.Info.Title <> "" Then ApplicationTitle.Text = My.Application.Info.Title Else ApplicationTitle.Text = System.IO.Path.GetFileNameWithoutExtension(_ My.Application.Info.AssemblyName) End If Version.Text = System.String.Format(Version.Text, _ My.Application.Info.Version.Major, _ My.Application.Info.Version.Minor) Copyright.Text = My.Application.Info.Copyright As you can guess, this is the code from the default splash screen template. What it does is set the values for the labels on the splash screen. Next add a timer control to the splash screen. We will initialize this control in the same onLoad event call of the mySplahScreen. Let�s name our timer control 'timerSplash'. I am also declaring the following shared variables: Collapse Public Shared opacityRate As Double = 0.0 Public Shared maximizeRate As Boolean = True Public Shared minimizeRate As Boolean = False Public Shared killApplication As Boolean = False Now let�s add code to our OnLoad event procedure, right after setting the Copyright text: Collapse Me.Opacity = 0.0 timerSplash.Interval = 50 timerSplash.Enabled = True timerSplash.Start() In the first line, I am setting the form�s opacity, i.e. the splash screen�s opacity equal to zero� Thus in the initial stage it will not be visible. Then I am setting the timerSplash�s interval equal to 50, making it enabled, and then telling it to start execution. With this ends our splash screen�s onLoad procedure. What remains is the timer tick event handler, i.e. the function which handles the event timerSplash.Tick. The timerSplash_Tick function will get called after every interval. An interval of 1000 is equal to 1 second. The interval we set is a small fraction of that second. Let�s add the code for this event handler: Collapse If opacityRate >= 1.0 Then opacityRate = opacityRate + 1.0 If opacityRate >= 20.0 Then 'Try 'Dim tempBoolean As Boolean = DataLayer.Open() 'If tempBoolean = False Then 'killApplication = True 'End If 'Catch ex As Exception 'killApplication = True 'End Try opacityRate = 0.99 Me.Opacity = opacityRate End If ElseIf maximizeRate Then opacityRate = opacityRate + 0.025 Me.Opacity = opacityRate If opacityRate >= 1.0 Then maximizeRate = False minimizeRate = True End If ElseIf minimizeRate Then opacityRate = opacityRate - 0.025 If opacityRate < 0 Then opacityRate = 0 End If Me.Opacity = opacityRate If Opacity <= 0.0 Then minimizeRate = False maximizeRate = False End If Else timerSplash.Stop() timerSplash.Enabled = False timerSplash.Dispose() Me.Close() End If What the above code does is: when the splash screen is called, it materializes into view stays solid for a second and then materializes back. During initialization I am setting four variables. Out of which three; opacityRate, minimizeRate, and maximizeRate, are used in this splashTimer_Tick event handler. By default, on initialization, the minimizeRate is set to false, the maximizeRate is set to true, and the opacityRate is set to 0.0. Furthermore, the opacity property of the form/splash-screen is also set to zero. One can easily grasp how the splashTimer_Tick function works, so I won�t be going into details of that. What is important to note here is this: After the first 10 ticks, i.e. the first � second, the form achieves maximum opacity, after the next 20 ticks (1 second) the minimizeRate is set to true so that the form loses opacity in the next 10 ticks (� second). The splash screen is thus displayed for a total of 2 seconds. At first this did wonders for me, I used the splash screen call version 0.01, the splash screen showed up before the startup form, and as it closed the main application form appeared. Then I decided to add a test to myMainForm. What I wanted to do was to check whether SQL Express existed and if I could connect to it. In my DataLayer.vb file, which I�ll discuss in detail when I get to SQL Express, I created a function Open that returns true if connection to the database is successfully established, else it returns false. After the splash screen call version 0.01, I added the following code to the myMainForm_OnLoad event: Collapse Dim tempBoolean As Boolean = DataLayer.Open() If tempBoolean = False Then Dim tempForm As New myMessageBox tempForm.Text = "Error!" tempForm.lblHeader.Text = "Database Communication Error!!!" Dim temp(2) As String temp(0) = "An error occurred while communicating with database. Please check if SQL Express is Running or that it exists." temp(1) = "" temp(2) = "Application will now exit." tempForm.txtMessage.Lines = temp tempForm.ShowDialog() Me.Close() End If The result was as predicted, after showing the splash screen, the application checked for connectivity with the database and if it failed showed a message box and then exited. It is important to mention here that I am using a custom message box, myMessageBox, as shown in Figure 6. Another important thing to note is that on calling the showDialog function, the execution is transferred to the form/dialog being showed, thus Me.Close is called only when the message box is closed. In the best case, when the database connection was established, this worked really good, but when the database could not be connected, it took its sweet time. Thus, after the splash screen closed, a long interval came before either myMessageBox or myMainForm was displayed. I then transferred the database connectivity check from myMainForm_OnLoad event to myMainForm_OnShown event� At least the main application form was displayed right after the closing of the splash screen. But still, when the application got to checking the database connection, myMainForm hung execution, and a long delay followed if the connection could not be established. In the end I decided to add the code to the splash screen. I added the code in the splashTimer_Tick function, when the splash screen had achieved its full opacity. The only thing that needed to be catered was that we could not call Application.Exit() from the splash screen as that generated errors (myMainForm hadn�t been initialized completely on splash screen call). Thus I created another shared variable, the fourth variable killApplication. In the splashTimer_Tick event, if you were to uncomment the commented code, that would handle the connectivity check. What it does is simple, by default killApplication is initialized to false, but if connectivity fails, all that needs to be done here is to set killApplication to false. Then I made some changes in myMainForm_OnLoad event. I wanted to somehow grab the value of killApplication, so that I would know if connectivity has failed or succeeded. Using splash screen call version 0.01, I found that we did not have access to the splash screen's shared variables from another form. Then I tried using splash screen call version 0.02, and it turned out that I had access to those variables. This was due to the following reason: if an object is created of a form, the shared variables are only accessible by that object and are specific to that object only, but if a form is called as it is, its shared variables are accessible globally. Thus, in the end I had the following two functions: Collapse Private Sub myMainForm_Load(...,...) Handles MyBase.Load mySplashScreen.ShowDialog() Dim tempObject As New ctrlMain Me.myPanel.Controls.Clear() Me.myPanel.Controls.Add(tempObject) End Sub Private Sub myMainForm_Shown(...,...) Handles MyBase.Shown If mySplashScreen.killApplication Then Dim tempForm As New myMessageBox tempForm.Text = "Error!" tempForm.lblHeader.Text = "Database Communication Error!!!" Dim temp(2) As String temp(0) = "An error occurred while communicating with database. Please check if SQL Express is Running or that it exists." temp(1) = "" temp(2) = "Application will now exit." tempForm.txtMessage.Lines = temp tempForm.ShowDialog() Me.Close() End IfIf End Sub After this resulted in what I wanted, I decided to add another splash screen, a screen that will be displayed when the user quits the application, my endScreen, as shown in Figure 7: Collapse Private Sub endScreen_Load(..., ...) Handles MyBase.Load timerExit.Interval = 1500 timerExit.Enabled = True timerExit.Start() End Sub Private Sub timerExit_Tick(..., ...) Handles timerExit.Tick timerExit.Stop() timerExit.Enabled = False timerExit.Dispose() Me.Close() End Sub As in the previous splash screen, mySplashScreen, I have included a timer in this one too. In the Load event I am setting the timer�s interval equal to 1500 (1.5 seconds), making it enabled, and starting its execution. On timer tick, I am stopping the timer, disabling it, disposing it off, and closing the splash screen. I am calling the splash screen from myMainForm�s FormClosing event. The following is the code for it: Collapse Private Sub myMainForm_FormClosing(..., ...) Handles MyBase.FormClosing Me.Hide() endScreen.ShowDialog() Try DataLayer.Close() Catch ex As Exception End Try End Sub As explained earlier, calling the endScreen using ShowDialog() instead of Show() makes it unnecessary to halt the execution of FormClosing. One thing I forgot to mention is that the connection established in mySplashScreen is the one used throughout this application, and on exit I am closing it. The connection is closed here in the FormClosing event of myMainForm. Important: If you want your splash screens to work around the edges, i.e. the form ends where the image does even if it isn�t rectangular, then make your splash screen images either .PNG or .GIF. Look at figure 5, it is the splash screen that I am using, if I click somewhere outside the edge of the image, I click the desktop. Similarly, look at figure 10; if I click anywhere that is not on the image, even the area in between the green border, then I click on the desktop. I am going to include the splash screen�s .PNG image in the resources folder; you can change the background image of mySplashScreen and set it to the image shown in Figure 10 to see how it works. But remember, this feature is automated for Visual Studio 2005 only, this doesn�t work in Visual Studio 2003 or in earlier versions. SQL Express Adding a SQL Express database to your application is as easy as adding a Windows Forms. Just right-click on your project in the Solution Explorer and select Add>New Item. Select the SQL database from the listed Visual Studio installed templates, it should appear if you have installed SQL Express. Click on Add. The database is created and an icon appears in the Solution Explorer. A new window pops up, this is the default dataset builder. Close it, as we won�t be using that. Double click on the database from the Solution Explorer and the database is loaded into the server explorer. To add a new table, right-click on Tables folder and select Add New Table, and to add a new stored procedure, right-click on Stored procedures and select, Add New Stored Procedure. I won�t go into how-to of defining tables and stored procedures, but I�d like you to take your time and explore SQL Express, especially the query builder, which is quite handy in building complex queries. Note: An application can contain more than on SQL Express database. Let�s start on DataLayer.vb, this is the class containing all the functions and calls to the database. I declared two shared variables; Collapse Public Shared dataCommand As New Data.SqlClient.SqlCommand Public Shared sqlConnection1 As New Data.SqlClient.SqlConnection(...) The parameter to Data.SqlClient.SqlConnection is the connection string. You can create your own, or get the one auto-generated. Click the database in server explorer, the properties tab will show the database�s properties, (clicking on the database in the solution explorer also shows the properties but not all of them, especially not the connection string). Use the connection string by copying it from the properties tab and pasting it in the DataLayer. Next we have to open a connection to the database: Collapse Public Shared Function Open() As Boolean Try dataCommand.CommandType = Data.CommandType.StoredProcedure dataCommand.Connection = sqlConnection1 sqlConnection1.Open() If sqlConnection1.State = Data.ConnectionState.Open Then Return True Else Return False End If Catch ex As Exception Debug.Write("While Opening the connection to the DB: " + _ ex.Message) Return False End Try End Function And that�s all there is to it� Next let�s see how to get data from the database using a stored procedure: Collapse Public Shared Function selectDetails(ByVal id As String) As _ Data.SqlClient.SqlDataReader Dim reader As Data.SqlClient.SqlDataReader Try dataCommand.CommandText = "selectDetails" dataCommand.Parameters.Clear() dataCommand.Parameters.Add("@id", Data.SqlDbType.VarChar) dataCommand.Parameters("@id").Value = id reader = dataCommand.ExecuteReader() Return reader Catch ex As Exception Debug.Write(ex.Message) Return Nothing End Try End Function The function above takes a parameter ID, calls a stored procedure 'selectDetails' from the database, passing along the ID as its parameter. An important thing to note here is that since I am using a shared dataCommand object, it is important to call dataCommand.Parameters.Clear() for each function as the wrong number of parameters can result in a lot of errors. The previous function was using a SqlDataReader to read from the database� What if we didn�t want to do that? An alternative is using a DataSet. The following function calls a stored procedure and stores the result in a DataSet. Collapse Public Shared Function selectAllRecord() As Data.DataSet Dim ds As New Data.DataSet Try Dim adapter As New Data.SqlClient.SqlDataAdapter adapter.SelectCommand = New Data.SqlClient.SqlCommand(_ "selectAllRecord", sqlConnection1) adapter.Fill(ds, "tblAddressBook") Return ds Catch ex As Exception Debug.Write(ex.Message) Return Nothing End Try End Function Similarly, we can execute non-queries (updates, insert, etc.) using dataCommand.executeNonQuery(). Furthermore, we can use views, functions, and many more in SQL Express to enhance our application. One thing that I�ll definitely be looking into is using more than one database in an application, when data between them has to be cross-referenced. Who knows� maybe that�ll be my next article� Other stuff!!! The main emphasis in this article was on Paneled Forms, splash screens, and SQL Express, but apart from that, when you download the application/code, you will find a very rich usage of TreeView control (figures 8 and 9), crystal reports, and rich and colorful dialogs. And all things must come to an end� I hope you found this article interesting and informative. As I said in my previous article, I am open for suggestions and remarks, both negative and positive. Feel free to contact me at msk.psycho@gmail.com. Hopefully I�ll be back soon with another article. Till then� Bye. License This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL) About the Author msalmank Web Developer Pakistan Member I am currently working as a Senior Software Developer (.Net) in Premier POS, Inc. Focused mainly on Windows Application Development, i am now looking for inspiration to work on Windows Presentation Foundation.
A guide to using Paneled Forms, Multi-Splash Screens, SQL Express, and many more in Windows Application Development
最新推荐文章于 2024-05-24 20:25:13 发布