Building a Windows Forms Control using the Virtual Earth Web Services

The process of building a Windows Forms Control is relatively simple – you are really just adjusting the way the control renders on the screen.  This typically means overriding the default paint behaviour to render the map image you want to display.  For a summary of how you can download a map image using the Virtual Earth Web Service you may want to check out this post.

Start by overriding both the OnPaint and OnBackgroundPant

protected override void OnPaint(PaintEventArgs e)
{
    base.OnPaint(e);
}

protected override void OnPaintBackground(PaintEventArgs e)
{
    // Do nothing – this is important to reduce flicker
}

Now you need to actually do the painting within the OnPaint method. This is done by calling the DrawImage method that exists on the Graphics object from the PaintEventArgs.

protected override void OnPaint(PaintEventArgs e)
{
    base.OnPaint(e);
   
    e.Graphics.DrawImage(this.controlImage, new Point(0,0));
}

The controlImage that is being displayed here is the map image that is downloaded via the DownloadImageFromUri method (see this post). This image needs to be updated whenever the Centre of the map or the Zoom changes.  For example on the control you may have properties that invoke a method to do the download:

public Location CentreOfMap
        {
            get
            {
                return centreOfMap;
            }
            set
            {
                if(centreOfMap == null || 
                  !centreOfMap.Equals(value) && value!=null)
                {
                    centreOfMap = value;

                    LoadMapData();
                }
            }
        }

        public int Zoom
        {
            get
            {
                return this.zoom;
            }
            set
            {
                if (this.zoom != value && value>0 && value<=19)
                {
                    this.zoom = value;

                    LoadMapData();
                }
            }
        }

The method LoadMapData handles all the calls to the Imagery service to get the map uri, followed by a call to the DownloadImageFromUri method, followed by triggering a refresh of the control (ie to get the control to repaint). 

Note that you need to be careful of threading here. You don’t want to be going off and downloading map images on the UI thread (most like the Centre and Zoom properties will be modified when the control is loaded – ie on the UI thread) as this will cause the UI to appear to freeze.  However, you need to issue the command to refresh the control (either Refresh or Invalidate) back on the UI thread.  This can be done by calling Invoke and providing the delegate to invoke on the UI thread. eg

this.Invoke(new System.Threading.ThreadStart(Refresh));

Leave a comment