另一个线程创建的表单中的STAThread错误

时间:2014-05-25 16:04:22

标签: c# multithreading forms sta

在我的服务器类收到所有必要信息后,它会触发一个应该创建新表单的事件。单击此表单上的按钮时,我得到 ThreadStateException 。我知道我应该在主线程中打开一个表单,但是当一个事件设置滚动时,表单在另一个线程中创建。我实现了MVC模式。我的主要方法确实有[STAThread]注释。

我的服务器是起点:

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;

目前可见的表格订阅了" onGameStarted" event并调用此方法:

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

当我实现MVC模式时,控制器随后被视图调用:

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();
}

此方法最终抛出异常

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;
    }

有谁能告诉我如何更改代码,以便不抛出任何异常? 谢谢!

1 个答案:

答案 0 :(得分:1)

我刚刚得到了解决方案。我决定不删除这篇文章,而是发布我的解决方案。

我检查了订阅 onGameStarted 事件的表单的 InvokeRequired 属性,然后调用了主线程。我略微改变了StartGame()方法:

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