从来自 c# 线程的列表框中读取所有数据的逻辑问题

Logic issue on reading ALL data from the from the listbox that is coming from thread in c#

我正在修改第一题尝试。

我需要帮助从列表框传递数据并将其传递给另一个方法,因此每次列表框获取数据时从踏板添加它,它也应该将该数据发送到我的新方法并将其发送到我的列表,因为在那种方法中,我将进行一些解析,因为来自列表框的数据是一个长字符串条形码,但我不需要解析数据的帮助,因为我可以做到,我只需要帮助的部分是从线程传递数据将它传递到列表框它也应该发送到我的方法 ReadAllData() 所以在那个方法中我将接收数据然后我将解析 make a return.

这是存储列表框并从 telnet 端口 23 的线程接收数据的方法

这是我需要将数据从 lst_BarcodeScan 发送到方法 ReadAllData 方法并存储到我的列表中的代码。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Sockets;
using System.Runtime.Remoting.Messaging;
using System.Security.Authentication.ExtendedProtection;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace BarcodeReceivingApp
{
    public class TelnetConnection
    {
        private Thread _readWriteThread;
        private TcpClient _client;
        private NetworkStream _networkStream;
        private string _hostname;
        private int _port;
        private BarcodeReceivingForm _form;
        private bool _isExiting = false;

        public TelnetConnection(string hostname, int port)
        {
            this._hostname = hostname;
            this._port = port;
        }

        public TelnetConnection()
        {

        }

        public void ServerSocket(string ip, int port, BarcodeReceivingForm f)
        {

            this._form = f;
            try
            {
                _client = new TcpClient(ip, port);
            }
            catch (SocketException)
            {
                MessageBox.Show(@"Failed to connect to server");
                return;
            }


            _networkStream = _client.GetStream();
            _readWriteThread = new Thread(ReadWrite);
            //_readWriteThread = new Thread(() => ReadWrite(f));
            _readWriteThread.Start();
        }


        public void Exit()
        {
            _isExiting = true;
        }

        public void ReadWrite()
        {

            var received = "";
            do
            {
                received = Read();
                if (received == null)
                    break;

                if (_form.lst_BarcodeScan.InvokeRequired)
                {
                    _form.lst_BarcodeScan.Invoke(new MethodInvoker(delegate
                    {
                        _form.lst_BarcodeScan.Items.Add(received + Environment.NewLine);
                    }));
                }    

            } while (!_isExiting);



            CloseConnection();


        }

    public List<string> ReadAllData()
    {
        var obtainData = new List<string>();



       return obtainData;
    }

        public string Read()
        {
            var data = new byte[1024];
            var received = "";

            var size = _networkStream.Read(data, 0, data.Length);
            if (size == 0)
                return null;

            received = Encoding.ASCII.GetString(data, 0, size);

            return received;
        }

        public void CloseConnection()
        {
            MessageBox.Show(@"Closed Connection",@"Important Message");
            _networkStream.Close();
            _client.Close();
        }
    }
}

Main class 将从 telnetconnection class 或我将添加的任何其他 classes 调用方法。

using System;
using System.Windows.Forms;

namespace BarcodeReceivingApp
{
    public partial class BarcodeReceivingForm : Form
    {
        //GLOBAL VARIABLES
        private const string Hostname = "myip";
        private const int Port = 23;
        private TelnetConnection _connection;


        public BarcodeReceivingForm()
        {
            InitializeComponent();

            //FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
            WindowState = FormWindowState.Maximized;
        }

        private void btn_ConnectT_Click(object sender, EventArgs e)
        {
            _connection = new TelnetConnection(Hostname, Port);
            _connection.ServerSocket(Hostname, Port, this);

        }

        private void btn_StopConnection_Click(object sender, EventArgs e)
        {
            //_connection = new TelnetConnection(Hostname, Port);
            //_connection.ServerSocket(Hostname, Port, this);
            _connection.Exit();
        }

        private void btn_RemoveItemFromListAt_Click(object sender, EventArgs e)
        {
            for (var i = lst_BarcodeScan.SelectedIndices.Count - 1; i >= 0; i--)
            {
                lst_BarcodeScan.Items.RemoveAt(lst_BarcodeScan.SelectedIndices[i]);
            }
        }

        private void BarcodeReceivingForm_Load(object sender, EventArgs e)
        {
            lst_BarcodeScan.SelectionMode = SelectionMode.MultiSimple;
        }

        private void btn_ApplicationSettings_Click(object sender, EventArgs e)
        {
            var bcSettingsForm = new BarcodeReceivingSettingsForm();
            bcSettingsForm.Show();
        }

        private void btn_ClearBarcodeList_Click(object sender, EventArgs e)
        {
            lst_BarcodeScan.Items.Clear();
        }
    }
}

在不增加线程复杂性的情况下实现的最简单方法是在添加项目时在 listbox 上简单地引发一个事件。问题是 listbox 没有任何允许这样做的事件,但您可以使用十几行代码创建自己的版本。

目标是创建 listbox 的派生控件,然后向其添加一个方法,在添加项目和宾果游戏时触发自定义事件。

这是自定义 listbox class 和自定义 EventArgs.

// custom override class over the list box so we can create an event when items are added
public class ListBoxWithEvents : ListBox
{
    // the event you need to bind to know when items are added
    public event EventHandler<ListBoxItemEventArgs> ItemAdded;

    // method to call to add items instead of lst.Items.Add(x);
    public void AddItem(object data)
    {
        // add the item normally to the internal list
        var index = Items.Add(data);

        // invoke the event to notify the binded handlers
        InvokeItemAdded(index);
    }

    public void InvokeItemAdded(int index)
    {
        // invoke the event if binded anywhere
        ItemAdded?.Invoke(this, new ListBoxItemEventArgs(index));
    }
}

// basic event handler that will hold the index of the item added
public class ListBoxItemEventArgs : EventArgs
{
    public int Index { get; set; } = -1;
    public ListBoxItemEventArgs(int index)
    {
        Index = index;
    }       
}

现在您需要将 form 上的 listbox 改为 ListBoxWithEvents。你有两种方法可以做到这一点,但我会给你最简单的方法。编译您的代码并为 form 设计 window。在您的工具箱中,您现在应该有 ListBoxWithEvents 控件,您可以简单地拖放 form 并替换您已有的控件。由于它源自 listbox,所以它所具有的只是额外的功能。它没有失去它以前的任何东西。

现在你需要改变两件事。在你的 form select 新的 ListBoxWithEvents 控件中,进入属性事件,你会发现名为 ItemAdded 的新事件,你可以双击它,它应该会创建一个事件像下面这样。我还提供了一个示例 MessageBox,它显示了您需要的所有内容。

private void ListBox1_ItemAdded(object sender, ListBoxItemEventArgs e)
{
    MessageBox.Show("Item was added at index " + e.Index + " and the value is " + listBox1.Items[e.Index].ToString());
}

最后,为了触发该事件,您需要使用新方法 lst.AddItem(object); 而不是 lst.Items.Add(object);,因此根据您的示例代码,您需要更改它:

_form.lst_BarcodeScan.Invoke(new MethodInvoker(delegate
{
    _form.lst_BarcodeScan.Items.Add(received + Environment.NewLine);
}));

对此:

_form.lst_BarcodeScan.Invoke(new MethodInvoker(delegate
{
    _form.lst_BarcodeScan.AddItem(received + Environment.NewLine);
}));

尝试一下,现在您应该会在每次向列表中添加内容时触发该事件。

由于您是编程新手,我发现重要的是要提及此事件将在 UI 线程而不是您创建的线程上触发。这意味着它的正常行为就像单击 button 会触发 button_click(object sender, EventArgs e) 事件一样。不涉及任何特殊线程。