在c#中从不同的类和线程更新GUI

时间:2016-04-19 09:57:53

标签: c# multithreading class user-interface

我是编程新手,只是想知道我得到的问题的解决方案是否合适。

我想将一个状态(字符串)写入一个创建Socket的类的文本框中,该类侦听要接收的数据(在另一个线程中)。

这就是我所做的:

单击按钮,在Form.cs中创建类:

 private void button_Create_Click(object sender, EventArgs e)
    {
        int port;
        Int32.TryParse(textBox_Port.Text, out port);
        ServerSocketClass serverSocket = new ServerSocketClass(port, this);
    }

ServerSocketClass看起来像:

class ServerSocketClass
{
    Socket ServerSocket;
    Socket Accepted;
    IPEndPoint LocalEndpoint;
    int Port = 1337; // just for fun
    Messenger MainForm;

    public ServerSocketClass(int port, Messenger form)
    {

        MainForm = form;

        if (port != 0)
            Port = port;
        ServerSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        LocalEndpoint = new IPEndPoint(IPAddress.Any, Port);

        MainForm.writeToMessages("Binding Endpoint to Socket...");
        ServerSocket.Bind(LocalEndpoint);

        MainForm.writeToMessages("Starting ServerListener Thread...");
        Thread ServerListenThread = new Thread(startListening);
        ServerListenThread.Name = "ServerListenerThread";
        ServerListenThread.Start();        
    }

    private void startListening()
    {            
        ServerSocket.Listen(5);

        MainForm.writeToMessages("Whaiting for incoming connections...");
        Accepted = ServerSocket.Accept();
        whaitForData();
    }

并更新表单类中的GUI我创建了一个委托和一个带有调用的“update”方法:

public delegate void writeMessege(string message);    
public writeMessege MessegeDelegate;
public void writeToMesseges(string messege)
    {
        if (InvokeRequired)
        {
            this.Invoke(MessegeDelegate, new object[] { messege });
            return;
        }
        textBox_Messeges.AppendText("SYSTEM: " + messege + "\n");
    }

它有效,但我想知道这是否是一种“有效”的方式,或者我应该去开发者地狱; - )

提前致谢

洛克

3 个答案:

答案 0 :(得分:0)

这是一种非常有效的方法,尽管它是否正确"很大程度上取决于上下文 - 你调用它的频率,你想在其中做什么,以及你需要调用它的代码。有许多不同的方法可以在不调用的情况下完成它,但使用InvokeRequired / Invoke没有任何问题 - 这就是它的用途。您可以使用一个调用自身的更新方法,这几乎与您的代码相同,但稍微不那么详细:

public void WriteMessages(string message)
{ 
  if (InvokeRequired)
  { this.Invoke(new Action<string>(WriteMessages), new object[] { message }); }
  else
  { textBox_Messages.AppendText("SYSTEM: " + message + "\n"); }
}

Invoke / InvokeRequired上已有很多帖子。作为起点,检查: Isn't blindly using InvokeRequired just bad practice?

答案 1 :(得分:0)

我有类似的情况,我有一个从其他类调用的类,有许多单独的线程,我不得不从所有其他线程更新一个特定的表单。因此,在表单中使用表单中的处理程序创建委托和事件就是答案。所以我想分享它,因为它似乎更简单(即使不一定是更好的解决方案)。

对我有用的解决方案:

  1. 我在类中创建了一个事件,我想在另一个表单上进行更新。 (当然,我首先在类中实例化了表单(称为SubAsstToolTipWindow)。

  2. 然后我使用此事件(ToolTipShow)在我想要更新标签的表单上创建一个事件处理程序。像魅力一样工作。

  3. 我使用this description执行更新的类中设计我自己的代码:

    public static class SubAsstToolTip
    {
        private static SubAsstToolTipWindow ttip = new SubAsstToolTipWindow();
        public delegate void ToolTipShowEventHandler();
        public static event ToolTipShowEventHandler ToolTipShow;
    
        public static void Show()
        {
            // This is a static boolean that I set here but is accessible from the form.
            Vars.MyToolTipIsOn = true; 
            if (ToolTipShow != null)
            {
                ToolTipShow();
            }
        }
    
        public static void Hide()
        {
            // This is a static boolean that I set here but is accessible from the form.
            Vars.MyToolTipIsOn = false;
            if (ToolTipShow != null)
            {
                ToolTipShow();
            }
        }
    }
    

    然后我的表单中的代码已更新

    public partial class SubAsstToolTipWindow : Form
    {
        public SubAsstToolTipWindow()
        {
            InitializeComponent();
            // Right after initializing create the event handler that 
            // traps the event in the class
            SubAsstToolTip.ToolTipShow += SubAsstToolTip_ToolTipShow;
        }
    
        private void SubAsstToolTip_ToolTipShow()
        {
            if (Vars.MyToolTipIsOn) // This boolean is a static one that I set in the other class.
            {
                // Call other private method on the form or do whatever
                ShowToolTip(Vars.MyToolTipText, Vars.MyToolTipX, Vars.MyToolTipY);     
            }
            else
            {
                HideToolTip();
            }
    
        }
    

答案 2 :(得分:0)

很久以前,但我希望你们都知道我最终解决了这个让我完全满意的事情(用事件解决了 - 当然; - )):

我定义了一个EventArgs来传递我想传递的所有信息:

public class IncomingMessageEventArgs : EventArgs
{
    private Message _message;
    public Message Message
    {
        get
        {
            return _message;
        }
    }

    public IncomingMessageEventArgs(Message message)
    {
        _message = message;
    }

}    

在发布信息的类(到WPF - 表单)上定义事件及其处理程序:

public delegate void IncomingMessageEventHandler(object sender, IncomingMessageEventArgs e);
    public event IncomingMessageEventHandler IncomingMessageEvent;
    protected void OnIncomingMessageEvent(IncomingMessageEventArgs e)
    {
        if (IncomingMessageEvent != null)
            IncomingMessageEvent(this, e);
    }

当然,如果需要更新WPF表格(也在&#34;信息发送类&#34;),则提升事件:

 OnIncomingMessageEvent(new IncomingMessageEventArgs(message));
在WPF类上

你需要监听事件,但首先要定义一个EventHandler,因为你的信息来自一个不同的线程!! :     private delegate void writeMessageToChatEventHandler(object sender,IncomingMessageEventArgs e);

现在我们编写我们的方法将处理引发的事件:

// Write to Chat
    private void writeMessageToChat(object sender, IncomingMessageEventArgs e)
    {
        try
        {
            if (!Dispatcher.CheckAccess())
            { 
                Dispatcher.Invoke(new writeMessageToChatEventHandler(writeMessageToChat), new object[] { sender, e } );
                return;
            }
            textBox_Chat.AppendText(e.Message.getFormatedMessageText() + "\n");
        }
        catch (Exception ex)
        {
            writeLogToChat(this, new IncomingLogEventArgs("ERROR: " + ex.Message));
        }
    }

最后,我们需要订阅事件当然(第一种方法,你可以忽略,它只是为了满足MS Nameing约定:

private void ClientSocket_IncomingMessageEvent(object sender, IncomingMessageEventArgs e)
    {
        writeMessageToChat(sender, e);
    }

ClientSocket.IncomingMessageEvent += ClientSocket_IncomingMessageEvent;

希望我这样做是可以理解的:P 感谢所有人对我的帮助!

再见