0

I have a little MVC Pattern application that creates UDP packets with random data, and constantly sends it

The main view contains the controller:

public partial class MainForm : Form
    {
        private MainController controller;

        public MainForm(MainController c)
        {
            controller = c;
            InitializeComponent();
        } 
    //...
    }

The main button click event calls the method that will eventually start the emulation. I wrap it around a try-cath block so I can display any exception on the view

    public partial class MainForm : Form
    {
    //...
        private void btnInitiate_Click(object sender, EventArgs e)
        {
           try
           {
             controller.initiateEmulation(txtData.Text);
           }
           catch (Exception ex)
           {  
            MessageBox.Show(ex.Message + ex.StackTrace, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
           }
        }
     }


public class MainController:IMainController
{
    private Emulator model;

    public void initiateEmulation(string data)
    {
        model = new Emulator(data);
    }
}


public class Emulator
    {
        private Thread emulatorThread;
        public String data;

        public Emulator(string data)
        {
            this.data = data;
            emulatorThread = new Thread(Emulate);
            emulatorThread.Start();
        }

        private void Emulate()
        {
            //CREATES SOCKET
            while (true)
            {
              //SENDS RANDOMIZED DATA
            }       
        }
    }

Problem is, my try-catch block is only capturing exceptions occurring in the main thread

How can I handle exceptions inside emulatorThread so I can show them on the view, the same as in the main thread?

minusnine
  • 85
  • 10

1 Answers1

3

A couple of interesting ways that you could handle this sort of thing, not too sure if these are "best practices", you may need to do a bit of research if you're not familiar with the concepts

first is delegate:

public class MainForm
    {
        private Emulator _emulator;

        public MainForm()
        {
            _emulator = new Emulator("data", HandleEmulatorException);
        }

        public void Render()
        {
            // Do other stuff
        }

        public void HandleEmulatorException(Exception e)
        {
            Console.WriteLine(e.Message);
        }
    }

    public class Emulator
    {
        private Thread emulatorThread;
        public String data;
        public OnException OnError;

        public delegate void OnException(Exception e);

        public Emulator(string data, OnException onError)
        {
            OnError = onError;
            this.data = data;
            emulatorThread = new Thread(Emulate);
            emulatorThread.Start();
        }

        private void Emulate()
        {
            while (true)
            {
                try
                {
                    throw new Exception("Exception was thrown");
                }
                catch (Exception e)
                {
                    OnError(e);
                }
            }
        }
    }

Here I give the emulator a delegate that it can call each time an exception happens, you can also do this with functions/actions:

public class MainForm
    {
        private Emulator _emulator;

        public MainForm()
        {
            _emulator = new Emulator("data", HandleEmulatorException);
        }

        public void Render()
        {
            // Do other stuff
        }

        public void HandleEmulatorException(Exception e)
        {
            Console.WriteLine(e.Message);
        }
    }

    public class Emulator
    {
        private Thread emulatorThread;
        public String data;
        public Action<Exception> OnError;


        public Emulator(string data, Action<Exception> onError)
        {
            OnError = onError;
            this.data = data;
            emulatorThread = new Thread(Emulate);
            emulatorThread.Start();
        }

        private void Emulate()
        {
            while (true)
            {
                try
                {
                    throw new Exception("Exception was thrown");
                }
                catch (Exception e)
                {
                    OnError(e);
                }
            }
        }
    }

Same concept but you don't have to declare a delegate, events is another one:

public class MainForm
    {
        private Emulator _emulator;

        public MainForm()
        {
            _emulator = new Emulator("data");
            _emulator.OnError += HandleEmulatorException;
        }

        public void Render()
        {
            // Do other stuff
        }

        public void HandleEmulatorException(Exception e)
        {
            Console.WriteLine(e.Message);
        }
    }

    public class Emulator
    {
        private Thread emulatorThread;
        public String data;
        public event OnException OnError;

        public delegate void OnException(Exception e);

        public Emulator(string data)
        {
            this.data = data;
            emulatorThread = new Thread(Emulate);
            emulatorThread.Start();
        }

        private void Emulate()
        {
            while (true)
            {
                try
                {
                    throw new Exception("Exception was thrown");
                }
                catch (Exception e)
                {
                    OnError(e);
                }
            }
        }
    }

Again similar concept but you don't have to pass in a delegate but you do have to declare one.

Hope this helps

Mark Davies
  • 1,447
  • 1
  • 15
  • 30
  • I got it working using your first example. However, beware that while you can use WriteLine or create Message Boxes inside HandleEmulatorException, manipulating any element in the view will result in an InvalidOperationException saying "Cross-thread operation not valid: Control 'fooBar' accessed from a thread other than the thread it was created on." Fixed it following this: https://stackoverflow.com/questions/10775367/cross-thread-operation-not-valid-control-textbox1-accessed-from-a-thread-othe Thanks a lot! – minusnine Jan 24 '18 at 13:46