使用线程不起作用,但如果代码在win形式内,则有效

时间:2014-02-26 17:38:54

标签: c# .net multithreading winforms backgroundworker

我已经找到了解决问题的方法,但我还没找到。

我正在编写一个将连接到irc服务器的机器人。我希望用户可以访问win表单窗口,在该窗口中可以输入服务器,频道等。

这是窗口:

enter image description here

我已将控制台输出设置为使用主程序中的代码更新我的文本框。有了这个,我将所有来自子类的文本都放到我的文本框中。

static class Program
{
    private static Form1 Form1;
    /// <summary>
    /// The main entry point for the application.
    /// </summary>
    [STAThread]
    static void Main()
    {

        using (var consoleWriter = new ConsoleWriter())
        {
            consoleWriter.WriteLineEvent += consoleWriter_WriteLineEvent;

            Console.SetOut(consoleWriter);
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Form1 = new Form1();
            Application.Run(Form1);
        }
    }

    static void consoleWriter_WriteLineEvent(object sender, ConsoleWriterEventArgs msg)
    {
        var message = msg.Value;
        Form1.statusTextBox.AppendText(message + "\r\n");
    }
}

public class ConsoleWriter : TextWriter
{
    public override Encoding Encoding { get { return Encoding.UTF8; } }

    public override void Write(string value)
    {
        if (WriteEvent != null) WriteEvent(this, new ConsoleWriterEventArgs(value));
        base.Write(value);
    }

    public override void WriteLine(string value)
    {
        if (WriteLineEvent != null) WriteLineEvent(this, new ConsoleWriterEventArgs(value));
        base.WriteLine(value);
    }

    public event EventHandler<ConsoleWriterEventArgs> WriteEvent;
    public event EventHandler<ConsoleWriterEventArgs> WriteLineEvent;
}

public class ConsoleWriterEventArgs : EventArgs
{
    public string Value { get; private set; }
    public ConsoleWriterEventArgs(string value)
    {
        Value = value;
    }
}

现在,当我点击“Connect”按钮时,我在Form1中调用它:

 gbaIrcBot.Connect(server, null, port, nick, channelList);

在gbaIrcBot.Connect()中,我还有:

    private void ReadStream()
    {
        string inputLine;
        while ((inputLine = _streamReader.ReadLine()) != null)
        {
            var splitInput = inputLine.Split(new[] { ' ' });
            if (splitInput.ElementAt(0) == "PING") { Pong(splitInput.ElementAt(1)); continue;}

            switch (splitInput.ElementAt(1))
            {
                case "001":         foreach (var channel in ChannelList) JoinChannel(channel);  break;
                case "PRIVMSG":     ProcessPrivMsg(splitInput);                                 break;
                case "433":         SetNick("AlternativeBOT");                                  break;
                default: Console.WriteLine(inputLine); break;
            }
        }
    }

此方法负责读取irc服务器的所有输入。当我从服务器收到消息时,我将其发送到控制台,该控制台更新Form1中的文本框。它必须是一个无限循环。

如果我不创建一个线程来保持我的UI不被冻结,这一切都很有效。这是一个例子:

enter image description here

当我尝试创建一个线程时,My Form1抛出一个异常,说它是一个跨线程的消息,我不能从外面更新它。

有什么想法解决它?

2 个答案:

答案 0 :(得分:0)

必须在UI线程上执行WinForms UI更新。试试这种方法:

How to update the GUI from another thread in C#?

答案 1 :(得分:0)

表单上的更新必须在窗口更新线程中完成。

您可以使用BeginInvoke()打包来强制执行此类线程。

更改

Form1.statusTextBox.AppendText(message + "\r\n");

Form1.BeginInvoke(() => Form1.statusTextBox.AppendText(message + "\r\n"));