null
null

Reputation: 1443

STAThread error in Form created by another Thread

After my server class received all necessary information, it fires an event that is supposed to create a new Form. When clicking on a button on this form, I get an ThreadStateException. I know that I should alawys open a form within the main thread., but as an event sets the ball rolling, the form is created in another thread. I implement the MVC pattern. My main method does have the [STAThread] annotation.

My Server is the starting point:

private void HandleClient(TcpClient client)
{
    PACKET_ID packetID = ServerHelper.ReadPacketID(client);

    switch (packetID)
    {       
        case PACKET_ID.START_GAME: // start a new game => create a new Form
            onGameStarted(); // fire event
            break;

The currently visible form subscribed the "onGameStarted" event and invokes this method:

private void StartGame()
{
    Invoke((MethodInvoker)delegate() { Hide(); });
    controller.StartGame(); // call controller to replace model and view
    Close();
}

As I am implementing the MVC pattern, the controller is then called by the view:

public void StartGame()
{
    GameModel gameModel = new GameModel(model.PlayerData); // new model ("model" is the old model)
    GameView gameView = new GameView(model.PlayerData); // new view (which needs to be run in a STAThread
    SetViewModel(gameView, gameModel);
    gameView.ShowDialog(); // show new form
}

public void SetViewModel(IView<GameModel> view, GameModel model)
{
    // set/replace new view and model
    this.viewGame = view;
    this.model = model;
    // add controller
    this.viewGame.AddController(this);
    this.viewGame.SubscribeEvents(model);
    viewGame.InitGUI();
}

This method finally throws the exception

public partial class GameView : Form, IView<GameModel>
{   
    //...
    private void buLoadMap_Click(object sender, EventArgs e)
    {

        OpenFileDialog objDialog = new OpenFileDialog();
        objDialog.Filter = "txt files (*.txt)|*.txt|All files (*.*)|*.*";
        if (objDialog.ShowDialog() == DialogResult.OK) // ThreadStateException
        {
            laError.Text = "Selected Map: " + objDialog.FileName;
            controller.LoadOwnMap(objDialog.FileName);

        }
        buLoadMap.Enabled = false;
    }

Can anyone tell me how to change the code, so that no exception is thrown? Thanks!

Upvotes: 0

Views: 207

Answers (1)

null
null

Reputation: 1443

I just got the solution. I decided not to delete this post but to publish my solution.

I checked the InvokeRequired attribute of the form that subscribes to the onGameStarted event and then invoked the main thread. I slightly changed the StartGame() method:

private void StartGame()
{
    if (this.InvokeRequired)
    {
        Action invoke = new Action(StartGame);
        this.Invoke(invoke);
    }
    else
    {
        Hide();
        controller.StartGame();
        Close();
    }
}

Upvotes: 1

Related Questions