Plunging into .NET Development

Weblog Pieter Gheysens
Microsoft .NET Development - C# - Enterprise Library - Visual Studio 2005 Team System - Compuware DevPartner - ...
 


Thursday, February 24

Binding combobox to an array

In this sample I will bind an array that contains all months to a combobox. A structure Month will be used instead of a class. A struct type is a value type [a class type is a reference type] that can contain constructors, constants, fields, methods, properties, indexers, operators, events, and nested types. The objects of struct types are always created on the stack and struct types are more useful for lightweight data structures that have value semantics.

        private struct Month

        {

            private int monthId;

            private string monthName;

 

            public Month(int monthId, string monthName)

            {

                this.monthId = monthId;

                this.monthName = monthName;

            }

 

            public int MonthId

            {

                get { return this.monthId; }

            }

 

            public string MonthName

            {

                get { return this.monthName; }

            }

        }


A simple private method getMonths is created that returns all months in an a Month-array.

        private Month[] getMonths()

        {

            Month[] months = new Month[]

                { new Month(1, "January"), new Month(2, "February"), new Month(3, "March"),

                    new Month(4, "April"), new Month(5, "May"), new Month(6, "June"),

                    new Month(7, "July"), new Month(8, "August"), new Month(9, "September"),

                    new Month(10, "October"), new Month(11, "November"), new Month(12, "December") };

 

            return months;

        }


Binding has now become simple : set the dataSource of the comboBox to the array and set the DisplayMember and ValueMember.

            this.cmbMonth.DataSource = this.getMonths();

            this.cmbMonth.ValueMember = "MonthId";

            this.cmbMonth.DisplayMember = "MonthName";


When an item is selected in the comboBox, you can retrieve the selected monthId and monthName by casting the SelectedItem to the Month structure.

            Month selectedMonth = (Month) this.cmbMonth.SelectedItem;


No backslash in Virtual Machine ?!!

By default, the Alt Gr key is the host key which allows the host OS to capture control over the mouse and keyboard from a virtual machine. As a result of this you are not able to type a backslash (\) in the virtual machine because pressing Alt Gr gives control back to the host OS. Very annoying if you really need this key ;-)

You can change this setting in the Virtual PC options (File > Options). Choose a key that you don't need very often or you're back in trouble!



Thx for helping me out David.

Tuesday, February 22

Controls disappear in designer

This happened to me already on a few occasions (in Visual Studio 2002 and 2003) and it now really starts bugging me! I have taken a closer look at it and I did some research about it so that I'm able to prevent this in the future (hopefully). I lost already quite some time to redesign my forms and I do not want to be in the same s*** again or at least I know what to do to recover quickly ...

Let me explain what exactly happens ... I'm designing a Windows Form with a tabControl and on each tabPage there's a userControl. When I make changes to this Windows Form, once in a while some of my userControls are removed from the tabPages without any specific reason. It appears - after comparing source files in source-control - that Visual Studio is removing lines of code in the InitializeComponent() method [Component Designer generated code] of the constructor in the form. The solution is still buildable because the private variables of my usercontrols are still declared, but the problem is that the instantiation doesn't occur anymore during the initialization and the usercontrol is therefore not visible anymore in the designer and it results in run-time errors : object reference not set to an instance of an object. Luckily we're using a source-control system and I'm able to rollback to a working version but this is REALLY annoying me because a lot of development-time is wasted. I can imagine that even more time is wasted (read this post in the Windows Forms Forum from a developer who really got frustrated) when you're not using a source-control system or when a lot of plain controls are removed from your form. In my case, I only had to reposition my usercontrols on the desired tabpages after having cleaned the declarations of the troubled usercontrols. I strongly advise you to do regularly check-ins when working with the designer. It's also known that changing code in the auto-generated code section often will give you troubles, but I'm sure that this didn't create the bug in my form because I really wasn't playing around with that code-section.

Finding a reliable reproduction for this bug is almost impossible because it seems to happen at any given moment. I hope that Microsoft has already resolved this designer-bug in the next release of Visual Studio. A patch for Visual Studio 2003 will also be appreciated by many developers I assume.

I've also googled the bug and a colleague gave me a good link with interesting tips when working with the designer. Here's an overview :
  • Check-in your design-forms as often as you can so that you're able to perform a rollback when needed.
  • Close all designer-windows before starting a build, before switching to release/debug and before closing your solution.
  • Build your entire solution before opening a designer-window.
  • Remove the references to the assemblies that contain the controls that vanished, and add them back again.
While I was finishing my post to publish it, I came across this post from Shawn Burke. It seems that the issue will be gone in Visual Studio 2005! Definitely one version too late for me and hotfixing it in VS 2003 looks very risky ;-(

Sunday, February 20

Line Chart Component [GDI+]

Well, this is how it looks like ...



It is not completely finished but it has already some functionality I would like to show you. As you can see, you can set all margins and the colors of the chart-components at run-time.

I will explain some functionality in more detail [note that source-code is better viewed on my blog-site instead of in a rss-reader] :
  • Curve class
    A curve class is created that will contain the X-values (DateTime array) and Y-values (array for doubles) for the line-chart. In the constructor the maximum and minimum are set.

    using System;

    using System.Drawing;

     

    namespace GraphComponent

    {

        public class Curve

        {

            #region Variables

            protected DateTime[] xValues;

            protected double[] yValues;

            private Color color;

            private System.Drawing.Drawing2D.DashStyle dashStyle;

            private double minimum = 0;

            private double maximum = 0;

            #endregion

     

            public Curve(DateTime[] newXValues, double[] newYValues)

            {

                this.xValues = newXValues;

                this.yValues = newYValues;

     

                //Max and Min

                this.setMaximum();

                this.setMinimum();

            }

     

            private void setMaximum()

            {

                for (int i=0; i < this.yValues.Length; i++)

                {

                    if (this.yValues[i] > this.maximum)

                    {

                        this.maximum = this.yValues[i];

                    }

                }

            }

     

            private void setMinimum()

            {

                for (int i=0; i < this.yValues.Length; i++)

                {

                    if (this.yValues[i] < this.maximum)

                    {

                        this.minimum = this.yValues[i];

                    }

                }

            }

        }

    }



  • Usercontrol Graph
    A usercontrol is created for displaying the graph-object. In the constructor of the usercontrol, the curve object is used as a parameter. In the paint-event of the graph-component, the width and height are set and the PaintEventArgs are passed to draw the graph.

            private void graph_Paint(object sender, System.Windows.Forms.PaintEventArgs e)

            {

                this.graph.UserControlWidth = ((GraphComponent.Graph)sender).Width;

                this.graph.UserControlHeight = ((GraphComponent.Graph)sender).Height;

     

                this.graph.DrawGraph(e);

            }


    The method DrawGraph is the most important method of the usercontrol because it's responsible for drawing all the chart-components on the display surface. The method is shown below without some regions that will be explained later ...

            public void DrawGraph(PaintEventArgs e)

            {

                //Variables - region left out

     

                //no drawing if no curve available

                if (this.currentCurve == null)

                    return;

     

                this.stepYValue = this.setScaling(this.currentCurve.Maximum);

     

                //Set Graphics-object

                Graphics grfx = e.Graphics;

     

                //Define maxWidth and maxHeight of graph

                this.maxWidth = this.userControlWidth - marginLeft - marginRight;

                this.maxHeight = this.userControlHeight - marginTop - marginBottom;

     

                //Set Font and Brush

                Font usedFont = new Font("Arial", 8.25F, FontStyle.Bold, GraphicsUnit.Point);

     

                //Main Area - region left out

     

                //Scales - region left out

     

                //Labels - region left out

     

                //Curves - region left out

            }


    The Graphics object is set via the PaintEventArgs and provides methods for drawing objects to the display surface. All default margins and colors are set in the constructor of the usercontrol and are read from the config-file. For filling graphical shapes, the SolidBrush class is used and this class inherits from the Brush class.

            public Graph(Curve newCurve)

            {

                InitializeComponent();   

     

                //set marges

                this.marginTop = Convert.ToInt32(ConfigurationSettings.AppSettings["marginTop"].ToString());

                this.marginBottom = Convert.ToInt32(ConfigurationSettings.AppSettings["marginBottom"].ToString());

                this.marginLeft = Convert.ToInt32(ConfigurationSettings.AppSettings["marginLeft"].ToString());

                this.marginRight = Convert.ToInt32(ConfigurationSettings.AppSettings["marginRight"].ToString());

     

                //set number of points on Y-axis

                this.numberOfYPoints = Convert.ToInt32(ConfigurationSettings.AppSettings["NumberOfYPoints"].ToString());

     

                this.currentCurve = newCurve;

     

                //Set default color and style

                this.currentCurve.Color = Color.FromName(ConfigurationSettings.AppSettings["LineColor"].ToString());

                this.currentCurve.DashStyle = System.Drawing.Drawing2D.DashStyle.Solid;

     

                //Set brushes

                this.brushMainArea = new SolidBrush(Color.FromName(ConfigurationSettings.AppSettings["BrushMainArea"].ToString()));

                this.brushChartArea = new SolidBrush(Color.FromName(ConfigurationSettings.AppSettings["BrushGraphArea"].ToString()));

                this.brushGrid = new SolidBrush(Color.FromName(ConfigurationSettings.AppSettings["GridColor"].ToString()));   

            }



    More details follow now on the regions that were left out in the DrawGraph method.
    • Main Area
      The main area consists of two rectangles. The second rectangle is part of the first one. The first rectangle is drawn from (0, 0) while the second one has to incorporate the specific margins. Both rectangles are filled with a brushColor.

                  #region Main Area

                  //Fill usercontrol

                  grfx.FillRectangle(this.brushMainArea, 0, 0, this.userControlWidth, this.userControlHeight);

       

                  //rectangle for graph

                  rectangle = new Rectangle(marginLeft, marginTop, this.maxWidth, this.maxHeight);

                  grfx.DrawRectangle(SystemPens.WindowText, rectangle);

                  grfx.FillRectangle(this.brushChartArea, rectangle);

                  #endregion


    • Scales/Grid
      The grid is created by drawing the X- and Y-lines. The Pen object with a certain color and a dashstyle is used for doing this task. A line is drawn from point (x1, y1) to point (x2, y2). The used margins, number of x-points, number of y-points, the width and height of the control stand central in the calculations of the different points.

                  #region Scales

                  Pen cPen = new Pen(this.brushGrid);

                  cPen.DashStyle = DashStyle.Dash;

                  int tempX1, tempY1, tempX2, tempY2;

       

                  for (int i=0; i < this.currentCurve.XValues.Length - 1; i++)

                  {

                      tempX1 = marginLeft + (int) (((this.maxWidth) / (this.currentCurve.XValues.Length)) * (i + 1));

                      tempY1 = marginTop;

                      tempX2 = marginLeft + (int) (((this.maxWidth) / (this.currentCurve.XValues.Length)) * (i + 1));

                      tempY2 = marginTop + this.maxHeight;

       

                      //Draw line for XValues

                      grfx.DrawLine(cPen, tempX1, tempY1, tempX2, tempY2);

                  }

       

                  for (int i=1; i < this.numberOfYPoints; i++)

                  {

                      tempX1 = marginLeft;

                      tempY1 = marginTop + i * ((this.userControlHeight - marginTop - marginBottom) / this.numberOfYPoints);

                      tempX2 = marginLeft + (this.userControlWidth - marginLeft - marginRight);

                      tempY2 = marginTop + i * ((this.userControlHeight - marginTop - marginBottom) / this.numberOfYPoints);

       

                      //Draw line for YValues

                      grfx.DrawLine(cPen, tempX1, tempY1, tempX2, tempY2);

                  }

       

                  cPen.Dispose();

                  #endregion


    • Labels
      For setting the labels a floating rectangle is used. This structure stores a set of four floating-point numbers that represents the location and size of a rectangle. The structure PointF represents an ordered pair of floating point x- and y-coordinates that defines a point in 2-dimensional plane. Naturally the margins, width and height are again important for the calculation of the locations.

                  #region Labels

                  RectangleF rectangleForLabel;

                  PointF pointFLocation;

                  //X

                  for (int i=0; i < this.currentCurve.XValues.Length; i++)

                  {

                      string label = this.currentCurve.XValues[i].Day + "/" + this.currentCurve.XValues[i].Month;

       

                      SizeF strSize = new SizeF(grfx.MeasureString(label, usedFont));

                      pointFLocation = new PointF(marginLeft + ((this.maxWidth) / (this.currentCurve.XValues.Length)) * i + - (strSize.Width / 2), this.maxHeight + marginTop + (strSize.Height / 2));

       

                      rectangleForLabel = new RectangleF(pointFLocation, strSize);

                      grfx.DrawString(label, usedFont, SystemBrushes.ControlText, rectangleForLabel);

                  }

       

                  //Y

                  for (int i=0; i <= this.numberOfYPoints; i++)

                  {

                      double label = (this.stepYValue * this.numberOfYPoints - ((this.stepYValue * this.numberOfYPoints - this.currentCurve.Minimum) / this.numberOfYPoints) * i);

       

                      string labelText = label.ToString();

       

                      SizeF strSize =  new SizeF(grfx.MeasureString(labelText, usedFont));

                      pointFLocation = new PointF(marginLeft - (strSize.Width * 1.2F), (marginTop + i * ((this.userControlHeight - marginTop - marginBottom) / this.numberOfYPoints)) - strSize.Height/2);

       

                      rectangleForLabel = new RectangleF(pointFLocation, strSize);

                      grfx.DrawString(labelText, usedFont, SystemBrushes.ControlText, rectangleForLabel);

                  }

                  #endregion


    • Curve
      Drawing the curve is nothing more than drawing lines from point (x1, y1) to point (x2, y2). These points are stored in a point array and are calculated from the value-points in the yValues-array, keeping in mind the margins, the width and height of the control, the number of x-points and the number of y-points.

                  #region Curves

                  //Set the color fo the pen

                  cPen = new Pen(this.currentCurve.Color, 3);

                  //Set the style of the curve (solid, dash, ...)

                  cPen.DashStyle = this.currentCurve.DashStyle;

                  //Set the Brush

                  cBrush = new SolidBrush(this.currentCurve.Color);                   

       

                  ptsList = new Point[this.currentCurve.XValues.Length];

       

                  int pointX = 0;

                  int pointY = 0;

       

                  Pen cPenExtra = new Pen(Color.Black);

                  cPenExtra.DashStyle = DashStyle.Solid;

       

                  for (int i=0; i < this.currentCurve.XValues.Length; i++)

                  {

                      pointX = marginLeft + (this.maxWidth / this.currentCurve.XValues.Length) * i;

                      pointY = (int) (marginTop + (this.maxHeight - ((this.currentCurve.YValues[i]) / (this.stepYValue * this.numberOfYPoints)) * this.maxHeight));

       

                      ptsList[i] = new Point(pointX, pointY);

       

                      if (i > 0)

                      {

                          //Draw line

                          grfx.DrawLine(cPen, ptsList[i-1], ptsList[i]);

                      }

                  }

                  #endregion

In a next post I will focus more on refreshing the chart with the margin- and color-values. I will also explain how the scaling (y-values) is done ...

Wednesday, February 16

Windows graphics design interface [GDI+]

This week - after a heavy bugfixing period of our application - I started again working on a component to create a custom chart. This is the first time that I am confronted with GDI+. GDI+ allows you to create graphics, draw text [+ lines and shapes], and manipulate graphical images as objects. You can use GDI+ to render graphical images on Windows Forms and controls. Cool stuff actually!

In my spare time I'm working on a more generic chart component for simple line charts where you can set the margins, colors, scales, ... at run-time.

Hopefully I can post some of my findings on this chart component next week-end.

Tuesday, February 15

Free Windows anti-spyware

All licensed Windows users will have anti-spyware protection at no charge.

The beta software was released in the beginning of January 2005. The software is now only available for customers running genuine Microsoft Windows [software was updated on January 27, 2005].

The Microsoft anti-spyware vision is that PC users should be able to see and understand the software that is running on their PCs and have the power to prevent or remove software they do not want. This vision drove the acquisition of GIANT Company Software, and it will inform Microsoft's efforts in future versions of its products.

Read article on ZDNet.com.

Compuware vs Sun

This evening we [Compmuware Belgium] played an indoor soccer game against Sun Belgium and guess what ... we won: 12-1! Thanks to Chris, Wout, Olivier, Wim, Kris and me! What a team!

If you want to challenge us, please let me know!

Wednesday, February 9

.NET Developer Roadmap

This roadmap might be interesting for those developers who want to know their current position in the ".NET world" and for those who want to plan a career-path. This document was already published by Microsoft at the end of 2002, but it may still be valuable. Read more here.

Monday, February 7

Compuware Showcases New DevPartner Products at VSLive!

Compuware Corporation (NASDAQ: CPWR) will give demonstrations of its two new DevPartner products, Compuware DevPartner Fault Simulator and Compuware DevPartner SecurityChecker at the VSLive! San Francisco 2005.
  • DevPartner Fault Simulator addresses the need of development and test teams to verify that the code written to handle error conditions is complete and functioning properly.
  • DevPartner SecurityChecker is a powerful security analysis tool that accelerates the development of ASP.NET applications by automatically identifying security vulnerabilities through a combination of compile-time analysis, run-time analysis and integrity analysis (attack simulation), pinpointing the location of vulnerabilities in the source code.
Read full news release.

At the conference there's also an Indigo Day : a full day of all-new content on Microsoft's critical approach to connectivity, Web services, and SOA. Sounds interesting! I believe that's content for the Dev & IT Pro Days 2006 ...

Thursday, February 3

50 Gmail-invitations !!

What happened overnight? Did the cost of diskspace fell down enormously?

Today I've opened my Gmail-account and noticed that I could give away 50 (yes : fifty!) Gmail-accounts! Or you could say 50 GB ...

Anyone interested in a Gmail-account? Mail me!

Update : Gmail gearing up for full launch?

My MSN Space

From now on, I will use my MSN space for more personal blogposts and for uploading some pictures. Yesterday-evening I've uploaded some pictures of the Dev & IT Pro Days 2005.

Wednesday, February 2

Dev & IT Pro Days - Day 2

Day 2 started very good with the keynote given by Kimberly Tripp : SQL Server 2005, Bridging the Gap between Development and Administration. I was really impressed with some new features of SQL Server 2005, especially with the "deep" CLR- and the XML-integration. Very promising stuff and nice presentation by Kimberly "SQL" Tripp.

Afterwards I was planning to follow the complete Visual Studio 2005 track. Because the first session of Visual Studio 2005 did not reveal many new things - probably because I already saw some presentations on TechEd last year - I switched to part 2 of the SharePoint track : Hardcore Development For SharePoint Products & Technologies. Patrick and Jan did a great job and gave some nice demos about InfoPath, BizTalk and SharePoint. Maybe I should also have followed part 1 ...

The sessions about Visual Studio 2005 Team System were great, especially the last one by Bart Vande Ghinste. He almost cancelled one of his demos because he couldn't enter the right password for his virtual machine and at the end he refused to stop in time because he insisted to show some extra things. He really showed interesting stuff about the new source control system, the integrated test system and the new build system.

Conclusion : the sessions of Day 2 were surely more a success for me than Day 1 and I must admit that today the voice-overs of the other room(s) were less annoying than Day 1. DevDays was of course also a great opportunity to meet some people and I was pleased to see that so many Compuware-colleagues were present at the event.

Tomorrow back to work and so back to reality : Visual Studio 2003 and an Oracle Database ;-).

Tuesday, February 1

Dev & IT Pro Days - Day 1

This morning - after a short night of sleep - I (together with 1300 other techies) was good on time for the kick-off of the Developer & IT Pro Days. After registration and a light breakfast, I hurried myself to the keynote-room because we were told that Bill would show up sharp and I didn't want to miss a thing ... but as you probably know, the session started with some delay! Bill did a quite short presentation about the importance of software and what to expect in the future : Visual Studio 2005, SQL Server 2005, Longhorn [WinFS, WinFX, Indigo, Avalon], ... Not really a fancy presentation but I was glad to be there. Following a live presentation given by someone like Bill Gates doesn't happen every week I presume.



The first "real" session of the day Closing The Gap Between Development And Operations: A Developer's Perspective was nothing more than giving some general advice for deploying applications. I ask myself if the application of the Enterprise Library (more specific the Logging Application Block) was in place in that session?! If you did not know yet : Enterprise Library v1.0 was released on Friday, January 28.

The session before lunch Sneak Preview Of The Future Of Web Development (ASP.NET 2.0) was more exciting with demos about data controls (databinding), master pages, themes/skins, administration, ...

After lunch, Clemens Vasters gave a presentation about Services and Service Oriented Architectures : Best Practices For SOA With Today's Technologies, but I had the feeling that the presentation time was really to short for him to deliver us his experiences.

Best Practices For Windows Forms Development was the last session of the day and I must say that I expected a little bit more advanced tips & tricks for developers.

Afterwards I followed the 5' Lightning Talks and I was surprised to witness the low attendance. Nevertheless, the courageous presenters did their best to bring their topic in a nutshell. Jelle, my new colleague at Compuware, talked about the release of Enterprise Library.