BeginInvoke within XNA

Started by
1 comment, last by briantee 8 years ago

 public delegate void LineReceivedEvent(string sentence);

 //serial port receive in its own thread
 private void sp_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
 {
    if (sp.IsOpen)
    {
       string sentence = sp.ReadLine();
       this.BeginInvoke(new LineReceivedEvent(LineReceived), sentence);
    }
 }


private void LineReceived(string sentence)
{
   textBoxRcv.AppendText(sentence);
   textBoxRcv.AppendText("\n");
}

I have this SerialPort code that works perfectly in a Windows.Form but not in XNA. I am reading gps data from a serial port, a single sentence, then want to use that data in the XNA game to plot a 3D path.

The error is BeginInvoke does not exist in the current context. I can of course get around this by using a ReadExisting in the update part of XNA without events or threaded but would really prefer the serial reading done in its own thread.

I made sure all references and "using's" were the same as the Windows.Form application.

I am using a Forms.Panel in the XNA window for buttons and the textbox. Everything works fine as long as i don't use BeginInvoke and the Serial Data Event.

Any suggestions?

Here is the code in its entirety:


using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;
using ButtonState = Microsoft.Xna.Framework.Input.ButtonState;
using Point = System.Drawing.Point;
using System.IO.Ports;
//using System.Threading;

namespace gpsPlot
{
    /// <summary>
    /// This is the main type for your game
    /// </summary>
    public class GPSMain : Microsoft.Xna.Framework.Game
    {        
        //Global Properties
        GraphicsDeviceManager graphics;
        Viewport vp;
        
        SpriteBatch spriteBatch;
        private Texture2D img;

        //panel objects and controls
        Panel pnl;   

        Button btnExit;
        Button btnOpenSerial;
        Button btnCloseSerial;

        ComboBox cboxPort;
        ComboBox cboxBaud;

        TextBox textBoxRcv;

        //serial related
        static string portName = "COM7";
        static int baudRate = 4800;

        SerialPort sp = new SerialPort(portName, baudRate, Parity.None, 8, StopBits.One);

        public delegate void LineReceivedEvent(string sentence);

        //serial port receive in its own thread
        private void sp_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
        {
            if (sp.IsOpen)
            {
                try
                {
                    string sentence = sp.ReadLine();
                    this.BeginInvoke(new LineReceivedEvent(LineReceived), sentence);
                }

                //this is bad programming, it just ignores errors until its hooked up again.
                catch (Exception) { }
            }

        }


        private void btnOpenSerial_Click(object sender, EventArgs e)
        {
            if (!sp.IsOpen)
            {
                sp.PortName = portName;

                sp.BaudRate = baudRate;

                sp.DataReceived += sp_DataReceived;
            }


            try { sp.Open(); }
            catch (Exception exc)
            {
                MessageBox.Show(exc.Message, "Not Connected to GPS");
            }

            if (sp.IsOpen)
            {
                //sp.ReadTimeout = 200;

                btnOpenSerial.Enabled = true;
                btnCloseSerial.Enabled = true;

                //update port status labels
                //this.labelPortStatus.Text = "Open";
                //this.labelPortName.Text = portName;
                //this.labelBaudRate.Text = Convert.ToString(baudRate);

                //discard any stuff in the buffers
                sp.DiscardOutBuffer();
                sp.DiscardInBuffer();

                if (!sp.IsOpen) return;
            }
        }


        private void btnCloseSerial_Click(object sender, EventArgs e)
        {
            try { sp.Close(); }
            catch (Exception exc)
            {
                MessageBox.Show(exc.Message, "Connection already terminated. Unplugged or shut off?");
            }

            btnOpenSerial.Enabled = true;
            btnCloseSerial.Enabled = false;
            //this.labelPortStatus.Text = "Closed";
            //this.labelPortName.Text = "-";
            //this.labelBaudRate.Text = "-";
            //Application.Exit();
        }

        private void LineReceived(string sentence)
        {
            //no matter what the line is, display it
            textBoxRcv.AppendText(sentence);
            textBoxRcv.AppendText("\n");
        }
        private void cboxPort_SelectedIndexChanged(object sender, EventArgs e)
        {

        }

        private void cboxBaud_SelectedIndexChanged(object sender, EventArgs e)
        {

        }


        public GPSMain()
        {
            graphics = new GraphicsDeviceManager(this);
            graphics.PreferredBackBufferWidth = 1400;
            graphics.PreferredBackBufferHeight = 768;

            Content.RootDirectory = "Content";

            // allow the mouse to remain visible and allow user resizing ofthe window
            this.IsMouseVisible = true;
            this.Window.AllowUserResizing = true;
            
            // create and setup the winform controls on the game window
            this.CreateControls();

            // hook into the client size change event so we can update the win form
            // controls and update the viewport on the graphics device
            this.Window.ClientSizeChanged += this.Window_ClientSizeChanged;

            //add available ports in port name combobox
            foreach (String s in System.IO.Ports.SerialPort.GetPortNames())
            {
                cboxPort.Items.Add(s);
            }
        }

 
        private void CreateControls()
        {
            // get game window as a win form Form class
            Form frm = Control.FromHandle(this.Window.Handle) as Form;
            
            // setup the panel control---------------------------------
            this.pnl = new Panel();
            this.pnl.Dock = DockStyle.Right;
            this.pnl.Width = 250;

            //Exit button-----------------------------------------------
            this.btnExit = new Button();
            this.btnExit.Location = new System.Drawing.Point(12, 12);
            this.btnExit.Name = "btnExit";
            this.btnExit.Size = new System.Drawing.Size(75, 23);
            this.btnExit.TabIndex = 0;
            this.btnExit.Text = "Exit";
            this.btnExit.UseVisualStyleBackColor = true;
            this.btnExit.Click += new System.EventHandler(this.btnExit_Click); 
            this.pnl.Controls.Add(btnExit);// add the button to the panel

            //Open Serial button----------------------------------------
            this.btnOpenSerial = new Button();
            this.btnOpenSerial.Location = new System.Drawing.Point(122, 146);
            this.btnOpenSerial.Name = "btnOpenSerial";
            this.btnOpenSerial.Size = new System.Drawing.Size(75, 23);
            this.btnOpenSerial.TabIndex = 0;
            this.btnOpenSerial.Text = "Open Port";
            this.btnOpenSerial.UseVisualStyleBackColor = true;
            this.btnOpenSerial.Click += new System.EventHandler(this.btnOpenSerial_Click);
            this.pnl.Controls.Add(btnOpenSerial);

            // 
            // btnCloseSerial--------------------------------------------------
            // 
            this.btnCloseSerial = new Button();
            this.btnCloseSerial.Location = new System.Drawing.Point(122, 185);
            this.btnCloseSerial.Name = "btnCloseSerial";
            this.btnCloseSerial.Size = new System.Drawing.Size(75, 23);
            this.btnCloseSerial.TabIndex = 1;
            this.btnCloseSerial.Text = "Close Serial";
            this.btnCloseSerial.UseVisualStyleBackColor = true;
            this.btnCloseSerial.Click += new System.EventHandler(this.btnCloseSerial_Click);
            this.pnl.Controls.Add(btnCloseSerial);

            // cboxPort---------------------------------------------------------
            // 
            this.cboxPort = new ComboBox();
            this.cboxPort.FormattingEnabled = true;
            this.cboxPort.Location = new System.Drawing.Point(16, 146);
            this.cboxPort.Name = "cboxPort";
            this.cboxPort.Size = new System.Drawing.Size(71, 21);
            this.cboxPort.TabIndex = 3;
            this.cboxPort.Text = "Port";
            this.cboxPort.SelectedIndexChanged += new System.EventHandler(this.cboxPort_SelectedIndexChanged);
            this.pnl.Controls.Add(cboxPort);
            // 
            // cboxBaud------------------------------------------------------------
            //
            this.cboxBaud = new ComboBox();
            this.cboxBaud.FormattingEnabled = true;
            this.cboxBaud.Items.AddRange(new object[] {
            "4800",
            "9600",
            "19200",
            "38400",
            "57600",
            "115200"});
            this.cboxBaud.Location = new System.Drawing.Point(17, 185);
            this.cboxBaud.Name = "cboxBaud";
            this.cboxBaud.Size = new System.Drawing.Size(70, 21);
            this.cboxBaud.TabIndex = 4;
            this.cboxBaud.Text = "Baud";
            this.pnl.Controls.Add(cboxBaud);
            this.cboxBaud.SelectedIndexChanged += new System.EventHandler(this.cboxBaud_SelectedIndexChanged);

            // textBoxRcv---------------------------------------------------------------
            // 
            this.textBoxRcv = new TextBox();
            this.textBoxRcv.BackColor = System.Drawing.SystemColors.ButtonHighlight;
            this.textBoxRcv.Location = new System.Drawing.Point(3, 43);
            this.textBoxRcv.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5);
            this.textBoxRcv.Multiline = true;
            this.textBoxRcv.Name = "textBoxRcv";
            this.textBoxRcv.ReadOnly = true;
            this.textBoxRcv.ScrollBars = System.Windows.Forms.ScrollBars.Vertical;
            this.textBoxRcv.Size = new System.Drawing.Size(230, 95);
            this.textBoxRcv.TabIndex = 17;
            this.pnl.Controls.Add(textBoxRcv);
 


            //add the panel to the game window form
            frm.Controls.Add(this.pnl);

        }

        //Event Handlers
        private void btnExit_Click(object sender, EventArgs e)
        {
            this.Exit();

        }

 
 
       void Window_ClientSizeChanged(object sender, EventArgs e)
        {
            // get the viewport from the graphics device
            vp = this.GraphicsDevice.Viewport;
            // change the viewport dimensions so that it is not drawn under any of our winform controls
            vp.Width = this.Window.ClientBounds.Width - pnl.Width;
            vp.Height = this.Window.ClientBounds.Height;
            // set the viewport back onto the graphics device
            this.GraphicsDevice.Viewport = vp;
            // update the label to display the rectangle info
            Rectangle rect = new Rectangle(vp.X, vp.Y, vp.Width, vp.Height);
            //lbl.Text = "Client: " + this.Window.ClientBounds.ToString() + "\r\n" +
            //           "Viewport: " + rect.ToString();

            this.Window.Title = "GPS Plotter";
        }


        protected override void Initialize()
        {
            this.Window_ClientSizeChanged(this, EventArgs.Empty);

            base.Initialize();
        }

        /// <summary>
        /// LoadContent will be called once per game and is the place to load
        /// all of your content.
        /// </summary>
        protected override void LoadContent()
        {
            // Create a new SpriteBatch, which can be used to draw textures.
            spriteBatch = new SpriteBatch(GraphicsDevice);

            // load a sample image that will be drawn the size of the viewport
            this.img = this.Content.Load<Texture2D>("Map2");

        }

        /// <summary>
        /// UnloadContent will be called once per game and is the place to unload
        /// all content.
        /// </summary>
        protected override void UnloadContent()
        {
            // TODO: Unload any non ContentManager content here
        }

        /// <summary>
        /// Allows the game to run logic such as updating the world,
        /// checking for collisions, gathering input, and playing audio.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Update(GameTime gameTime)
        {
            // Allows the game to exit
            if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
                this.Exit();

            // TODO: Add your update logic here

            base.Update(gameTime);
        }

        /// <summary>
        /// This is called when the game should draw itself.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.CornflowerBlue);

            // draw the image the same size of the viewport
            this.spriteBatch.Begin();
            //var vp = this.GraphicsDevice.Viewport;
            Rectangle rect = new Rectangle(vp.X, vp.Y, vp.Width, vp.Height);
            Rectangle srcrect = new Rectangle(0, 0, this.img.Width, this.img.Height);
            this.spriteBatch.Draw(this.img, rect, srcrect, Color.White);
            this.spriteBatch.End();


            base.Draw(gameTime);
        }
    }
}

Advertisement

If I'm understanding right...you're talking about a compile error?

Microsoft.Xna.Framework.Game doesn't have a function called BeginInvoke. Presumably your sp_DataReceived was declared in a type that extended a Form or some Control before you ported the code over to an XNA game. This is where MSDN documentation is your friend, as BeginInvoke is a method declared in System.Windows.Forms.Control.

You'll get an error if you try and modify state on a WinForm control from a thread that is not the UI thread (the thread that the controls are being run on). BeginInvoke allows you to send a message to the UI thread and perform an action that will update the UI at a later point in time. So call BeginInvoke on one of your WinForm controls and it should compile.

Awesome, thank you so much.

i changed it from:


this.BeginInvoke

//to the panel control pnl

pnl.BeginInvoke.... 


And yes it compiles and get serial port reads.

Thx again.

This topic is closed to new replies.

Advertisement