|
The newsletter is compiled by DevCity.NET NewsMasters Ged Mead and Mike McIntyre
Advertisement
.netCHARTING 2.1 - Image Is Essential
The best looking ASP.NET charts can now save you even more time with automated multi-chart drilldown, enhanced data integration, and a new template system. Version 2.1 continues to push the envelope for dynamic web based charting with 4 stunning new visual effects, two for bars / columns and two for bubbles. Download your free developer version today!
We at DevCity.NET, use .netCHARTING - give it a try too: http://www.dotnetcharting.com
Table Of Content:
Advertisement
I've found that the Splitter Control is a great friend, but if you're not careful it can be a really wicked enemy. Fail to treat it exactly the way it thinks it should be treated and it will extract total revenge on you - sitting there on your form and sulking like a spoilt child, absolutely refusing to move a single millimeter in any direction..
You've been there, too, huh?
It seems to me that the key to an unfrustrating relationship with our friend, the Splitter, is the "Three Steps to Heaven" method (not quite what Eddie Cochran had in mind, but then Visual Basic hadn't been invented when he was around.)
Step 1 is to add the first 'Container Control' to the form. Now, I know I'm misusing that expression slightly, but I wanted to get over the sense that it's a chunk of real estate that is most probably going to hold some other controls. A Panel or a GroupBox, maybe. But it could just as easily be a ListView or a TreeView though. You get the idea, I know.
So add a control of choice if you're feeling independent. I'm thinking though that it might be better - just so we're all marching in step here while we get through this - let's make it a Panel. Go ahead and add the Panel now.
For now, I'm assuming that we are going to take the easy option and have a 'Container' at the left, a Splitter in the middle, and a second 'Container' on the right. We'll maybe get a bit cocky later and try some fancy footwork once we're sure we know what we're doing.
Change the Dock property of the Panel to Left and it will automatically change size and hug the left hand side of the form. That's Step 1 out of the way.
Step 2, I suspect, is the place where most people miss a beat, stumble and generally bring the whole parade to a grinding tuneless halt. Because this is where we add the Splitter to the Form.
Ah, those three little words; so important to your future happiness. Sorry, no - not those three little words ... the words I had in mind were "to the Form". Because here's the scenario: you've just added a Panel, you go to the ToolBox, double click to add the Splitter and the Splitter will be added to the control that's currently selected. It's an odds-on bet that the control selected right now is the Panel, not the Form. Everything looks hunky-dory, but when you try to run the project, that darn Splitter just laughs in your face. Generally, I find that I'm not inclined to laugh back.
Anyway, the thing is that all you have to do is make sure you select the form itself, double click to add the splitter and leave the Splitter's Dock property at the default setting of Left. Change the BackColor of the Splitter so that it shows up nice and clearly. Fiddle around with the width so that a passing mouse will be able to land on it without a magnifying glass. Contrary to what the girls will tell you, size is important.
Step 3 just needs us to create our right hand side 'container' control and, at the risk of being boring, we'll make this another Panel. Once again, ensure that you don't insert this Panel into the existing panel, and that it is independently placed on the Form somewhere over to the right-hand side.
Change its Dock Property to Fill. It's a good idea to give the two panels different BackColors so that you can easily check that the Splitter is doing its job, so this would be a good moment to do that too. You might be content just to change the left Panel, but leave the right Panel the same color as the Form itself. Enough about backcolors, already.
OK, with those three steps completed in that order, run the project and hopefully you will have a Splitter control there that's going to be your best pal for the rest of the day. You'll probably find you can't resist tweaking the widths or locations of the two panels here and there, but this is normal and quite acceptable behavior between two consenting Panels. Just be careful, as my mother always used to warn me, that you don't go too far.
Anyway, there you are - three steps to Splitter heaven.
For the benefit of the brave-hearted and more adventurous among you, here's a quick walkthrough of the steps needed to create a form with three 'container' areas, one filling the left hand side and two to the right, one above the other. As before, you can mix and match which controls you use for this.
1. Add the left hand control. Dock it Left. Optionally, change its backcolor .
2. Add a Splitter control to the Form.. Increase its Width. Change its backcolor.
3. Add the bottom right control to the Form.. Dock it to the Bottom. Optionally, change its backcolor .
4. Add a second Splitter control to the Form.. Change its Dock property to Bottom. Increase its height a little and give it a different backcolor.
5. Add the third and final 'container' control to the Form, placing it somewhere up in the right-hand upper quarter of the form. Change its Dock property to Fill. Maybe give it a different backcolor too.
6. That's it. Run the project and you can now resize all three 'containers'.
I've certainly had some frustrating moments trying to produce Splitter/Panel configurations that really work, so I hope that sharing these steps with you will help keep you on track.
Now that you know how to avoid the unwanted pains of giving birth to that bonny bouncing Splitter control you always wanted, you can enjoy hearing the heart warming splitter-splatter of tiny triumphs.
- Junior (Ged Mead aka XTab, xtab@vbcity.com)
Operators
by Mike McIntyre
Division: \ V.S. /
Divide integral values with the \ (back slash) operator when you do not need decimal points or fractional values. The \ operator is the integral division operator and it is up to 10 times faster than the / (forward slash) operator.
Compound Assignment Operators: a += b V.S a = a + b
Compound assignment statements first perform an operation on an argument before assigning it to another argument. Example:
a += b
In the example above, b is added to the value of a, and that new value is then assigned to a. Compound assignment operators are more concise than their constituent operators (separate + and =). Compare the statement above to the one below. The statement above is a shorthand equivalent of the statement below.
a = a + b
Compound assignment operators are faster. If you are operating on an expression instead of a single variable, for example an array element, you can achieve a significant improvement with compound assignment operators.
Compound assignment operators for numbers:
Compound operator for strings: &= Example:
Dim a As String = "First "
a &= "Name"
Result: First Name
Concatenation: & V.S. +
Use the & concatenation operator instead of the + operator to increase the speed of concatenations. Performance of the & and + operators are only equivalent if both operands are type String. If not, the + operator is late bound and must perform type checking and conversions.
by HotDog
Can we Clone? -> MemberwiseClone
Often we want a second instance of an object, but with all the same (important) properties. We could of course go through all of them manually, making a sometimes very looooong list of objectB.Prop1 = objectA.Prop1: objectB.Prop2 = objectA.Prop2, etc, etc, etc. Or we could use the built in method of an Object: MemberwiseClone
Since Memberwiseclone is a protected method of the Object class, it can be called from within any class to create a copy of itself or its baseclass. For example, this class:
Class TestClass
Implements ICloneable
Public A As Integer, B As Long, C As String
Sub New(ByVal A As Integer, ByVal B As Long, ByVal C As String)
Me.A = A
Me.B = B
Me.C = C
End Sub
Public Function Clone() As TestClass
Return Me.MemberwiseClone
End Function
Public Function CloneAsObject() As Object Implements System.ICloneable.Clone
Return Me.Clone
End Function
Public Overrides Function ToString() As String
Return "A=" & A & " B=" & B & " C=""" & C & """"
End Function
End Class
The properties are none too exciting in themselves, but having to copy them one by one could become a tediously long list to begin with, but on top of that a maintenance nightmare: every time you change, add or delete a property, you'd have to change the Clone functionality as well. Forgetting to change it would not necessarily show at compile time, but could cause serious harm when running the program. That's why here the memberwise clone method is used. The ToString() function was added to easily see the current values as shown in this test code:
'first create an instance the normal way
Dim Org As New TestClass(5, 10, "This is a test")
'change a value to show that cloning isn't limited to start values
Org.A = Integer.MaxValue
MsgBox("Original: " & Org.ToString())
'Create a clone
Dim Clone As TestClass = Org.Clone
MsgBox("Cloned: " & Clone.ToString)
When run, the messageboxes will show that both instances contain the same values.
As mentioned, the MemberWise clone method is a protected method. That means you can't clone an object this way outside the object itself, you can however create a public function that returns the memberwiseclone as shown in the example above. The ICloneable interface has one function: Clone() that tells the framework that the object in question has the functionality to clone itself. Many classes in .NET, such as an array or a treenode, implement IClonable.
One important sidenote: when using MemberwiseClone, a shallow copy is made of the object. That means that object references inside the cloned object refer to the same object as the original object. In the example you can change A,B and C in the cloned object without changing the original. However if a variable D was added which points to an object (say a textbox) and you change a property (say, the Text) in the cloned class, the Text of the textbox in the original class will be changed as well: there is only one instance of TextBox. If the Clone functionality has to make a deep copy, at this point you will have no choice but to add that yourself.
by George Poth
Are you one of those users who prefers to use the X Button at the top right to close a program? Me, too. There's nothing wrong with this, apart from the detail that some programmers disregard this button and make users like me go nuts about this sometimes. Clicking this button may every so often mean that you lose the data you just put into the program, or there might go on something even more disastrous.
Be kind to your users and incorporate some code for this button so the program doesn't close without at least a confirmation from the user. Oh-oh! By now, I think you know I hate message boxes, so the example I'm giving here is really just an example. You can do something better than that, like saving everything that needs to be saved without annoying the user and then exit. Maybe you'd like to try the error provider which I suppose is there to get rid of those pesky message boxes.
For the code in the following, I assume you have a form named "frmXButton":
#Region "X Button Handling"
Private Sub frmXButton_Closing(ByVal sender As Object, _
ByVal e As System.ComponentModel.CancelEventArgs) Handles MyBase.Closing
'[Show a message when the X is clicked]
If MessageBox.Show("Do you like to be annoyed?", _
"I'm an annoying message box", MessageBoxButtons.YesNo, _
MessageBoxIcon.Information) = DialogResult.No Then
'[/Show a message when the X is clicked]
'[If user click NO then let form open]
e.Cancel = True
'[/If user click NO then let form open]
End If
End Sub
#End Region
by Mike McIntyre
Part 3 of 3
This installment of the article will explain how to begin using the AppMgr created in the previous installment to provide application services.
Here is how we left the AppMgr class at the end of the previous installment.
Friend Class AppMgr
<STAThread()> _
Shared Sub Main()
' Declare a variable named frm1 of type Form1.
Dim frm1 As Form1
' Instantiate (create) a new Form1 object and assign
' it to variable frm1.
frm1 = New Form1()
' Call the Application class' Run method
' passing it the Form1 object created above.
Application.Run(frm1)
End Sub
End Class
AppMgr is already providing some application services including:
1. Entry Point
Sub Main runs the application.
2. Proper Thread Model
is an attribute. It indicates that the application should join the Single-Threaded Apartment (STA). As a newbie you do not need to try to understand the concepts of attributes and the Single-Threaded Apartment until much later. What you can understand is that unless you include the _ above the Shared Sub Main() line drag and drop, the clipboard, and other things you will want your application to use WILL NOT WORK.
3. Starts the Application
Application.Run(frm1) begins running a standard application message loop on the current thread, and makes frm1 visible. As long a frm1 is open the application continues to run. Once frm1 is closed the application will end.
Add Application Services to the AppMgr Class
The AppMgr class can handle things that should be done before the application is run such as showing a Splash Form and/or authorizing the user with a LogIn Form.
Add two forms to the Visual Studio.NET VB.NET Windows Forms application you created in installment one of this article.
1. Add a new form named SplashForm.
2. Add a new form named LogInForm. To LogInForm add a new button named LogInButton. Set LogInButton's Text property to: LogIn. Set LogInButton's DialogResult property to OK.
Replace all AppMgr class code with the code below:
Friend Class AppMgr
<STAThread()> _
Shared Sub Main()
' Provide Splash Form service.
Dim SplashFrm As New SplashForm()
SplashFrm.ShowDialog()
' Provide Login service.
Dim LoginFrm As New LoginForm()
LoginFrm.ShowDialog()
' Declare a variable named frm1 of type Form1.
Dim frm1 As Form1
' Instantiate (create) a new Form1 object and assign
' it to variable frm1.
frm1 = New Form1()
' Call the Application class' Run method
' passing it the Form1 object created above.
Application.Run(frm1)
End Sub
End Class
Test Your Code
Run the project.
The SplashForm will open first. In a real application you would add a timer to hold the form open for a few seconds and then automatically close it. In this simple example click the close box (X) in the upper right corner to close the SplashForm.
The LoginForm will open next. In a real application you would provide a way for the user to enter a login id and a password, and code to validate the user against a file or database. If authorization is successful the application is run, if not it is never run. In this simple application click the LogIn button which will authorize the login.
Finally, if the LogInForm returns a DialogResult of OK the application will be run. If not, the application is never run.
Note: You can experiment to get a DialogResult that is not OK by clicking the close box (X) in the upper right corner of the LogInForm.
In this three part article you have learned about Sub Main and how to create a AppMgr class that can provide application services from startup to shut-down.
There are many other services that can be added to AppMgr such as a global exception handler and application form management that always keeps a reference to any application form accessible from any code in the application.
Do you want to know more about the AppMgr? Let me know. Write me at mikemc@getdotnetcode.com. If there is enough interest I will write a newsletter series that explains how to add other services to the AppMgr class.
Advertisement
.netCHARTING 2.1 - Image Is Essential
The best looking ASP.NET charts can now save you even more time with automated multi-chart drilldown, enhanced data integration, and a new template system. Version 2.1 continues to push the envelope for dynamic web based charting with 4 stunning new visual effects, two for bars / columns and two for bubbles. Download your free developer version today!
We at DevCity.NET, use .netCHARTING - give it a try too: http://www.dotnetcharting.com
by Mark Dryden
Sounds too easy? Well, off the top of my head I thought it was - that was until I scratched the surface a bit....
OK, the scenario - one button and one label, when the button is pressed it tests whether the label backcolor is red - if it is the label's backcolor is changed to green and vice-a-versa. So, quickly typed...
If Me.MyLabel.BackColor = Color.Red Then
Me.MyLabel.BackColor = Color.Green
Else
Me.MyLabel.BackColor = Color.Red
End If
However, this will not work as an equality comparison between the Color objects in not supported. So, how about the 'Is' operator...-
If Me.MyLabel.BackColor Is Color.Red Then
Me.MyLabel.BackColor = Color.Green
Else
Me.MyLabel.BackColor = Color.Red
End If
But again this doesn't work! Why, well the 'Is' operator only works for equality comparison between Reference Types, e.g. Classes, Strings and Arrays. The Color Object is not a class, in fact its a structure which is not classed as a Reference Type but as a Value Type. Luckily, the .NET defined structures such as color, char, etc. expose a equals method...
If Me.MyLabel.BackColor.Equals(Color.Red) Then
Me.MyLabel.BackColor = Color.Green
Else
Me.MyLabel.BackColor = Color.Red
End If
Phew! So the moral is check what type of object you are making the comparison against and ensure you are using the correct method.
[Note: there are other ways you can test the equality of a color such as using the Color.ToString and Color.ToARGB which tests just the ARGB values. Alternatively, the Color.op_Equality operator, which is the equilvalent of the C# '==' operator, will also test any state flags of structure as well]
Advertisement
|