从 C# 中的类更新 GUI 的正确方法

Posted

技术标签:

【中文标题】从 C# 中的类更新 GUI 的正确方法【英文标题】:Correct way to update a GUI from a class in C# 【发布时间】:2018-11-18 11:11:30 【问题描述】:

我正在寻找一种方法来从我想要独立而不依赖于 GUI 的类中更新 GUI。它是一个由监听器和客户端组成的网络类。这个类可以连接然后发送/接收数据。我希望这些数据能够使用 GUI 显示,但在类本身中没有任何与 GUI 相关的代码。

所以简而言之,网络类只知道自己。 GUI 知道网络类。

这是我要添加代码的地方

    public void ReceiveBytes()
    
        byte[] receivedPacket;

        while (IsListeningForBytes)
        
            receivedPacket = new byte[Packet.BUFFERSIZE];

            try
            
                int bytesRead = ClientSocket.Receive(receivedPacket, SocketFlags.None);

                if (bytesRead > 0)
                
                    SocketObject.ProcessMessage(receivedPacket);
                    // Update GUI here after the message has been processed.
                
                else
                
                    throw new Exception("No bytes read");
                
            
            catch (Exception ex)
            
                IsListeningForBytes = false;
                Disconnect();
                Console.WriteLine(ex.Message);
            
        
    

编辑:对不起大家,我会尽量让事情更清楚。我正在使用 Windows 窗体,为了这个练习,我们会说我有三个不同的控件:一个列表框、一个组合框和一个文本框,它们将根据发送的内容获取数据。 (我的实际应用程序有需要更新的列表框、组合框、复选框等)。

我知道我不应该从我的对象中引用 GUI,因此我的问题。

至于相关代码,不知道你想看什么。

我已阅读有关事件处理程序和委托的信息,但我不确定在这种情况下如何实际实现它。我最初将 GUI 更新方法作为操作传递给在需要时调用的类,但这似乎很冗长,并没有专门更新我想要的控件。

感谢您迄今为止的帮助。

【问题讨论】:

发布一些相关代码...顺便说一句,您可以使用Task 您使用的是哪个 UI 框架?表格?吗?控制台? 附言;如果您让调用者决定:只需实现要引发的事件。 很难猜出你想把数据放在哪里,但这里有一个例子,你有一个表单 1 中的文本框,你想从类 1 中填充它,然后制作一个方法,它需要一个字符串作为参数,并填充文本框。这个方法应该在 Form1 类中。然后从课堂上调用它。公共填充文本框(字符串数据) textBox1.Text = data; 然后从类 1 调用这个方法,如果你放一些代码,我们将能够提供更多帮助 【参考方案1】:

直接从您的对象更新您的 UI 将违反 OOP。

相反,实现一个事件让调用者/用户知道发生了什么事,并让他们负责更新 UI。

这是一个例子:

//added event, SomeDataObject is for you to create.
public event EventHandler<SomeDataObject> MessageProcessed;
public void ReceiveBytes()

    byte[] receivedPacket;

    while (IsListeningForBytes)
    
        receivedPacket = new byte[Packet.BUFFERSIZE];

        try
        
            int bytesRead = ClientSocket.Receive(receivedPacket, SocketFlags.None);

            if (bytesRead > 0)
            
                SocketObject.ProcessMessage(receivedPacket);
                // no UI update but fire an event
                MessageProcessed?.Invoke(this, new SomeDataObject());
            
            else
            
                throw new Exception("No bytes read");
            
        
        catch (Exception ex)
        
            IsListeningForBytes = false;
            Disconnect();
            Console.WriteLine(ex.Message);
        
    

见:

Understanding events and event handlers in C#

https://msdn.microsoft.com/en-us/library/db0etb8x(v=vs.110).aspx

https://duckduckgo.com/?q=EventHandler+C%23&t=h_&ia=qa

更新


那么,它是如何工作的:

在你的 FooGUI 类中,你需要订阅事件。

//so, your UI, can be a window, a form or ... console.
//I'll call your class BytesReceiver
public class FooGUI

     BytesReceiver _receiver = new BytesReceiver();

     //somewhere, in some function your listener has started
     void Init()
     
         //we added an event earlier, now attach a handler.
         //a handler is a function, bound to some signature (as defined by the delegate)
         //which will be executed when the event is triggered.

          //so again; we bind a function to the event, which is invoked when the event is 
          //raised.

          //keep in mind: the Invoke take place on the other thread; so the handler
          //runs on that same thread.

          //there is no magical polling taking place: it's just a 
          //function call (from receiver).

         //note: there are various ways to bind a function: I'll use lambda here
         _receiver.MessageProcessed += (sender,e) =>
         
             //update GUI here. 
         

         //since there your while loop waits for a long time
         //there must be some non-blocking operation, presumably on another thread.
         _receiver.StartListening();
     

【讨论】:

所以如果我使用你的例子,我如何从引发的事件中更新 GUI?我是否经常从 GUI 中寻找这个事件?这就是我感到困惑的地方。 我会更新答案。您可能想深入研究基本的事件处理。尝试教程;-)

以上是关于从 C# 中的类更新 GUI 的正确方法的主要内容,如果未能解决你的问题,请参考以下文章

无法从使用 c# 在不同线程上运行的另一个页面 User.cs 更新 GUI (MainWindow.xaml) 中的进度条

从 C# 中的类生成具有重复节点的 XML

如何从 Java 中的另一个线程更新 SWT GUI

在 C# 中的类构造函数中调用异步方法 [重复]

如何从 C# 中的 Web Api 方法正确获取字节数组?

从共享 ArrayPool 中租用和返回 C# 中的多维数组的正确方法?