HomeDigital EditionSearch Dotnet Cd
ASP.NET C# Certification Exams The CLI Data Access Editorials Extending .NET Fundamentals Interoperability Interviews Migrate Mobile .NET Mono .NET Interface Object-Oriented Programming Open Source Optimization Product/Book Reviews Security Source Code UML Visual Studio .NET

With the release of the .NET Compact Framework developers have a new platform for working in the mobile space. The .NET Compact Framework brings most of the namespaces and functionality of Windows Forms development and the .NET Framework to PDAs and other devices. This portability of code and knowledge also applies to components for the presentation layer. Whether you use your own custom-built controls or controls purchased from a third party, you can reap the benefits of lower development costs and a faster time to market using .NET Framework components within Compact Framework applications.

While Microsoft has done an outstanding job of maintaining similar interfaces in the Compact Framework and the .NET Framework, developers must realize that not all of the features of controls will transfer. Because of the nature of the underlying hardware, developers must remember that memory, CPU power, and other system resources are at a premium.

When it comes to control design, as with all Compact Framework applications, the general rule of thumb is "small is good." This applies not only to the amount of screen real estate the control uses, but also to the way control must be designed in the .NET Compact Framework.

If you develop a control that inherits from System.Windows.Control and then attempt to use that control in a Smart Device Application project, you will find that the control is grayed out in your toolbox. Since the control is not marked with any designer attributes for the .NET Compact Framework, a version must be compiled that uses an alternate version of the .NET Compact Framework libraries. These libraries are only intended to be referenced at design time. The standard location for these files is C:\Program Files\Microsoft Visual Studio .NET 2003\CompactFrameworkSDK\v1.0.5000\Windows CE\Designer.

The need to develop dual versions of your control allows you to place attributes or code in the control that will only be used by Visual Studio .NET at design time, while still reducing the footprint of your control at runtime. The issue this presents is how to make sure your runtime version and design time version are the same without maintaining two code bases.

The answer is to put both the designer and control solutions in the same library. Visual Studio .NET will not allow you to create two projects in the same directory. To get around this you will have to do a little work behind the back of Visual Studio .NET.

First create a new C# Smart Device Application project called BasicChart. Add a new class file called BasicChart.cs to this project. BasicChart.cs will be where the core control functionality will be located later.

After creating the first project, open another copy of Visual Studio .NET and create a second project called BasicChartDesigner (see Figure 1). The project will be a C# Windows Control Library project. Now close the second copy of Visual Studio .NET and copy the files shown in Figure 2 into the project directory for the BasicChart project.

Figure 1

Figure 2

By copying the solution files into the same directory you will be able to open the BasicChartDesigner project and, after deleting the UserControl1 file and the existing BasicChart.cs, you will be able to have both projects share the same code base.

In the BasicChartDesigner you will need to update your references to reflect the need to support "designer friendly" libraries. Delete the references to System.XML, System.Data, System.Drawing, and System .Windows.Forms, and add references to the System.CF.Design, System.CF.Drawing, and System.CF.Windows. Forms libraries from the C:\Program Files\Microsoft Visual Studio .NET 2003\CompactFrameworkSDK\v1.0.5000\Windows CE\Designer directory.

After you add these references you will need to add a reference to the System.Windows.Forms library. It is important to add the references in the correct sequence because the order in which you add them is the same order in which they are evaluated by the compiler.

With the project files set up and the references in place, you can begin coding the control and completing the BasicChart class. This control will use two ArrayList objects to hold the data for the chart (see Listing 1). In our example our chart will display profits by month.

The chart should display some data or image during design time to help the user position and size the control. For this introduction the control randomly generates five months of data to display (see Listing 2). The code is wrapped in a compiler directive so it will only be compiled into the assembly during design time. By only having the code in the designer we will be able to reduce the memory requirements and storage size of the component on the device.

In order for the control to render to the screen you will need to handle the onPaint event. To design for the extension of this control at a later time you will put the drawing logic in a separate function. Later, this control can be expanded to support additional chart types or rendering engines.

protected override void OnPaint(System.Windows.Forms.
PaintEventArgs e)
{
DrawDemoGraph("CF Graph", e.Graphics);
}

The DrawDemoGraph function will fetch a local copy of the ArrayLists to use for the X and Y axes of the chart. The number of items on the axes will help determine the size and width of each column.

ArrayList aX = Months;
ArrayList aY = Profits;

int MaxWidth = (ColWidth + ColSpace) * aX.Count + ColSpace;
int MaxColHeight = 0;
int TotalHeight = MaxHeight + XLegendSpace + TitleSpace;

After gathering the height information we will draw out the background for the chart. Because the Compact Framework supports a wide range of the System.Drawing namespace you are able to reuse a lot of drawing code you might already have from other GDI+ applications. This control uses the FillRectangle function to paint a white background with an ivory background.

objGraphics.FillRectangle(new SolidBrush(Color.White), 0, 0,
MaxWidth, TotalHeight);

objGraphics.FillRectangle(new SolidBrush(Color.Ivory), 0, 0,
MaxWidth, MaxHeight);

The control will compute the relative heights for the columns based on the values in the ArrayList object and prepare the fonts for the text items. After this is complete it is time to render the columns of our chart. Looping through each of the values in the Y axis ArrayList, the control will compute the height and position for the text string displaying the value above each column (see Listing 3).

The last thing the control needs to do is render the title at the bottom of the grid. That is done with a simple call to DrawString. The control uses the MaxHeight and XLegendSpace settings to control the vertical placement of the title.

objGraphics.DrawString(Title,fontTitle, objBrush, 0,
MaxHeight + XLegendSpace);

After compiling the designer and control project, all that is left is to test the control. You can do this by creating a new Smart Device Application project. Once the project is created, customize your toolbox by adding the BasicChart control. Remember to select the BasicChartDesigner.dll since this is for design time.

After placing and sizing a BasicChart control on a page, a few lines of code are needed in the page load event handler to populate the control with data. Since this is a test project, randomly generated data will be used for the first five months (see Figures 3 and Listing 4).

Figure 3

Listing 5 contains the complete code for BasicChart.cs should you wish to publish it.

Conclusion
Thanks to similarities between the .NET Framework and Compact Framework, developers are able to leverage their extensive knowledge and code bases when developing for the mobile world. The .NET Compact Framework continues the Microsoft tradition of allowing developers to build or buy rich presentation layer components that allow them to encapsulate and reuse functionality across applications. With a few easy steps you can begin building your own controls to reuse on your mobile development projects.

About The Author
Brad McCabe is a technology evangelist for .NET, ASP.NET, and .NET CF for Infragistics (www.infragistics.com), a leader in providing a broad infrastructure of reusable presentation-layer components essential for the creation of next-generation Web-based applications and XML Web services utilizing .NET, COM, and Java. brad@infragistics.com

	



Listing 1

private ArrayList months = new ArrayList();
private ArrayList profits = new ArrayList();


public ArrayList Months
{
    get { return months; }
    set { months = value; }
}


public ArrayList Profits
{
    get { return profits; }
    set { profits = value; }
}



Listing 2

public BasicChart()
{
#if DESIGN
    ArrayList _months = new ArrayList();
    ArrayList _profits = new ArrayList();


    _months.Add("Jan");
    _months.Add("Feb");
    _months.Add("Mar");
    _months.Add("Apr");
    _months.Add("May");


    Random _random = new Random();


    _profits.Add(_random.Next(1000, 9999));
    _profits.Add(_random.Next(1000, 9999));
        _profits.Add(_random.Next(1000, 9999));
    _profits.Add(_random.Next(1000, 9999));
    _profits.Add(_random.Next(1000, 9999));


    this.Months = _months;
    this.Profits = _profits;
#endif
}


Listing 3

CurrentHeight = (Convert.ToDouble(aY[iLoop]) /
Convert.ToDouble(MaxColHeight)) * Convert.ToDouble(MaxHeight - HeightSpace);


objGraphics.FillRectangle(objBrush, BarX, MaxHeight -
Convert.ToInt32(CurrentHeight), ColWidth, Convert.ToInt32(CurrentHeight));


objGraphics.DrawString(aX[iLoop].ToString(), fontLegend, objBrush, BarX,
MaxHeight);


objGraphics.DrawString(String.Format("{0:#,###}", aY[iLoop]), fontValues,
objBrush, BarX, MaxHeight - Convert.ToInt32(CurrentHeight) - 15);


BarX += (ColSpace + ColWidth);


Listing 4

ArrayList _months = new ArrayList();
ArrayList _profits = new ArrayList();


_months.Add("Jan");
_months.Add("Feb");
_months.Add("Mar");
_months.Add("Apr");
_months.Add("May");


Random _random = new Random();


_profits.Add(_random.Next(1000, 9999));
_profits.Add(_random.Next(1000, 9999));
_profits.Add(_random.Next(1000, 9999));
_profits.Add(_random.Next(1000, 9999));
_profits.Add(_random.Next(1000, 9999));


this.basicChart1.Months = _months;
this.basicChart1.Profits = _profits;


Listing 5

using System;
using System.Drawing;
using System.Collections;
using System.Windows.Forms;
using System.Collections.Specialized;


namespace Infragistics
{
    public class BasicChart : System.Windows.Forms .Control
    {
        // An arraylist containing all of the datapoints
        private ArrayList months = new ArrayList();
        private ArrayList profits = new ArrayList();


        public BasicChart()
        {
        #if DESIGN
            ArrayList _months = new ArrayList();
            ArrayList _profits = new ArrayList();


            _months.Add("Jan");
            _months.Add("Feb");
            _months.Add("Mar");
            _months.Add("Apr");
            _months.Add("May");


            Random _random = new Random();


            _profits.Add(_random.Next(1000, 9999));
            _profits.Add(_random.Next(1000, 9999));
                _profits.Add(_random.Next(1000, 9999));
                _profits.Add(_random.Next(1000, 9999));
            _profits.Add(_random.Next(1000, 9999));


            this.Months = _months;
            this.Profits = _profits;
        #endif
        }


        public ArrayList Months
        {
            get { return months; }
            set { months = value; }
        }


        public ArrayList Profits
        {
            get { return profits; }
            set { profits = value; }
        }


        public void DrawDemoGraph(string Title, Graphics objGraphics)
        {
            const int ColWidth = 25;
            const int ColSpace = 5;
            const int MaxHeight = 200;
            const int HeightSpace = 20;
            const int XLegendSpace = 30;
            const int TitleSpace = 20;
        
            ArrayList aX = Months;
            ArrayList aY = Profits;
 
            int MaxWidth = (ColWidth + ColSpace) * aX.Count + ColSpace;
            int MaxColHeight  = 0;
            int TotalHeight  = MaxHeight + XLegendSpace + TitleSpace;


            objGraphics.FillRectangle(new SolidBrush(Color.White), 0, 0,
			MaxWidth, TotalHeight);
            objGraphics.FillRectangle(new SolidBrush(Color.Ivory), 0, 0,
			MaxWidth, MaxHeight);


            // find the maximum value
            for (int iValue = 0; iValue < aY.Count; iValue++)
            {
                if (Convert.ToInt32(aY[iValue]) > MaxColHeight)
                    MaxColHeight = Convert.ToInt32(aY[iValue]);
            }


            int BarX  = ColSpace;
            double CurrentHeight;
        
            SolidBrush objBrush  = new SolidBrush(Color.Navy);
            Font fontLegend = new Font("Arial", 11, FontStyle.Regular);
            Font fontValues  = new Font("Arial", 8, FontStyle.Regular);
            Font fontTitle = new Font("Arial", 12, FontStyle.Regular);


            // loop through and draw each bar
        
            for (int iLoop = 0; iLoop < aX.Count; iLoop++)
            {
                CurrentHeight = (Convert.ToDouble(aY[iLoop]) /
Convert.ToDouble(MaxColHeight)) * Convert.ToDouble(MaxHeight - HeightSpace);


                objGraphics.FillRectangle(objBrush, BarX, MaxHeight -
Convert.ToInt32(CurrentHeight), ColWidth, Convert.ToInt32(CurrentHeight));
                objGraphics.DrawString(aX[iLoop].ToString(), fontLegend,
objBrush, BarX, MaxHeight);
                objGraphics.DrawString(String.Format("{0:#,###}",
	aY[iLoop]), fontValues, objBrush, BarX, MaxHeight -
				Convert.ToInt32(CurrentHeight) - 15);


                BarX += (ColSpace + ColWidth);
            }


            objGraphics.DrawString(Title, fontTitle, objBrush, 0, MaxHeight
			+ XLegendSpace);
        }


        protected override void OnPaint(System.Windows.Forms.PaintEventArgs e)
        {
            DrawDemoGraph("CF Graph", e.Graphics);
        }
    }
}

All Rights Reserved
Copyright ©  2004 SYS-CON Media, Inc.

  E-mail: info@sys-con.com