0
Answer

Object reference problems with events & multithreading

Chris

Chris

16y
2.3k
1

I'm currently writing a GPS map viewer application for Windows Mobile on the .NET CF 2.0. It uses a worker thread to constantly read data from the GPS receiver and raise events whenever the desired data is received (position and velocity data). There are also GpsStarted and GpsStopped events raised whenever the GPS receiver starts or stops reading data. These events are subscribed to on a Windows Form where the map is displayed.

Whenever the GpsStarted event is raised on the form, I attempt to create new instances of my arrow sprite (an orange arrow that points which direction you're going on the map), and the rectangle used to position the arrow on the screen. Then, whenever a velocity or position update is received from the GPS, in the event handler I decide whether or not to display the arrow by setting a class scope boolean variable and setting the Direction attribute of the arrow sprite. I then call the form's Invalidate() method to force the form to redraw itself, showing the updated map view and position.

Now here's where my problem comes in. Once the form's OnPaint and OnPaintBackground methods execute, the arrow sprite is a null reference and the arrow's rectangle is an empty rectangle, just as they were defined before; I thought they were set in the GpsStarted event.

The GPS receiver logic is packaged into a separate class library that is referenced by the main UI application. My problem descibed above concerns events that are defined in the GPS dll and subscribed to on the UI.

Here are the sections of my code that i'm having trouble with. Any help would be greatly appreciated.

public partial class frmViewer : Form

{   

   private bool mShowPositionArrow = false;

   private Bitmap mPositionArrow = null;

   private Rectangle mArrowRec = Rectangle.Empty;

   private Arrow mArrow = null;

 

   public void Gps_GpsStarted()

   {

      if (InvokeRequired)

      {

         try

         {

            GenericEventHandler d = new GenericEventHandler(Gps_GpsStarted);

            Invoke(d);

         }

         catch (ObjectDisposedException) { }

      }

      else

      {

         // create object references and set rectangle value

         mArrow = new Arrow();

         mArrowRec = new Rectangle(

            (ClientRectangle.Width / 2) - (Arrow.Size.Width / 2),

            (ClientRectangle.Height / 2) - (Arrow.Size.Height / 2),

            Arrow.Size.Width, Arrow.Size.Height);

      }

   }

 

   public void Gps_GpsStopped()

   {

      if (InvokeRequired)

      {

         try

         {

            GenericEventHandler d = new GenericEventHandler(Gps_GpsStopped);

            Invoke(d);

         }

         catch (ObjectDisposedException) { }

         }

      else

      {

         mArrow = null;

         mShowPositionArrow = false;

      }

   }

 

   protected override void OnPaint(PaintEventArgs e)

   {

      base.OnPaint(e);

 

      // mArrow = null and mShowPositionArrow = false here

      if (Program.Map != null)

      {

         e.Graphics.DrawImage(mMapControls.ZoomInImage,

            mMapControls.ZoomInRectangle, 0, 0,

            mMapControls.ZoomInRectangle.Width,

            mMapControls.ZoomInRectangle.Height, GraphicsUnit.Pixel, mImgAttr);

         e.Graphics.DrawImage(mMapControls.ZoomOutImage,

            mMapControls.ZoomOutRectangle, 0, 0,

            mMapControls.ZoomOutRectangle.Width,

            mMapControls.ZoomOutRectangle.Height, GraphicsUnit.Pixel, mImgAttr);

      }

   }

 

   protected override void OnPaintBackground(PaintEventArgs e)

   {

      try

      {

         if (Program.Map != null)

         {

            // mArrow = null and mShowPositionArrow = false here

            if (Program.Gps != null && Program.Gps.GpsState == DeviceState.Running &&

               mArrow != null && mShowPositionArrow)

            {

               // this code SHOULD execute

               mPositionArrow = mArrow.DirectionArrow;

               Program.Map.DrawScreen(ref e, ref mPositionArrow, ref mArrowRec);

            }

            else

            {

               // this code executes

               Program.Map.DrawScreen(ref e);

            }

         }

         else

         {

            e.Graphics.FillRectangle(mBackgroundBrush, ClientRectangle);

         }

      }

      catch (Exception ex)

      {

         Program.ShowError("Error", ex.Message);

      }

   }

 

   public void Gps_PositionChanged(Position position)

   {

      if (InvokeRequired)

      {

         try

         {

            PositionChangedHandler d = new PositionChangedHandler(Gps_PositionChanged);

            this.Invoke(d, new object[] { position });

         }

         catch (ObjectDisposedException) { }

      }

      else

      {

         try

         {

            if (Program.Map != null && position.FixQuality != FixQuality.Invalid)

            {

               // mArrow != null and mShowPositionArrow = true here

               if (Program.Map.GoToPosition((double)position.Longitude.Coordinate, (double)position.Latitude.Coordinate))

               {

                  // this code executes

                  mShowPositionArrow = true;

                  Invalidate();

               }

               else

               {

                  mShowPositionArrow = false;

               }

            }

         }

         catch (Exception ex)

         {

            Program.ShowError("Error", ex.Message);

         }

      }

   }

 

   public void Gps_VelocityChanged(Velocity velocity)

   {

      if (InvokeRequired)

      {

         try

         {

            VelocityChangedHandler d = new VelocityChangedHandler(Gps_VelocityChanged);

            this.Invoke(d, new object[] { velocity });

         }

         catch (ObjectDisposedException) { }

      }

      else

      {

         try

         {

            // mArrow != null and mShowPositionArrow = true here

            if (mShowPositionArrow && mArrow != null)

            {

               // this code executes

               mArrow.Direction = velocity.Direction;

               Invalidate();

            }

         }

         catch (Exception ex)

         {

            Program.ShowError("Error", ex.Message);

         }

      }

   }