简体   繁体   English

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

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

I am modifying to first question attempt. 我正在修改第一个问题尝试。

I need help passing the data from a listbox and pass it to another method so every time the listbox gets data add it from the tread, it should also send that data to my new method and it to the my list because in that method I will be doing some parsing because the data from the listbox is a long string barcode but I don't need help on parsing the data because I can do that, the part I need help only is to pass the data from thread that is passing it to the listbox it should also be send to my method ReadAllData() so in that method I will received the data and then I will do the parsing the make a return. 我需要帮助将列表框中的数据传递给另一个方法,因此,每次列表框获取数据时,都需要从胎面将其添加到数据中,它还应该将该数据发送到我的新方法以及我的列表中,因为在这种方法中,我会正在做一些解析,因为列表框中的数据是长字符串条形码,但我不需要解析数据的帮助,因为我可以做到这一点,我需要帮助的部分只是将数据从传递给它的线程传递给列表框,它也应该发送到我的方法ReadAllData(),因此在该方法中,我将接收到数据,然后进行解析以进行返回。

Here is the method where the listbox is stored and receives the data from a thread from telnet port 23 这是存储列表框并从telnet端口23的线程接收数据的方法

Here is the code I need to send the data from the lst_BarcodeScan to the method ReadAllData method and store to my list. 这是我需要将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 that will call the methods from the telnetconnection class or any other classes I will add. 主类,它将从telnetconnection类或我将添加的任何其他类中调用方法。

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

The easiest way to implement without adding more complexity to the thread is to simply raise an event on the listbox when and item is added to it. 在不增加线程复杂性的情况下实现的最简单方法是,在将和项添加到listbox时在listbox上引发一个事件。 The problem is that the listbox do no have any events that allow to do that but you can create your own version with a dozen lines of code. 问题是listbox没有任何允许执行此操作的事件,但是您可以使用十几行代码创建自己的版本。

The goal is to create a derived control of the listbox then you add to it a method to trigger a custom event when an item is added and bingo. 目标是创建listbox的派生控件,然后向其中添加一个方法,以在添加项目和宾果游戏时触发自定义事件。

Here's the custom listbox class with the custom EventArgs . 这是带有自定义EventArgs的自定义listbox类。

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

Now you need to change your listbox on your form with the ListBoxWithEvents instead. 现在,您需要使用ListBoxWithEvents来更改form上的listbox You have 2 ways to do this but i'll give you the easiest. 您有2种方法可以做到这一点,但我会给您最简单的方法。 Compile your code and go in the design window for the form . 编译代码,然后进入form的设计窗口。 In your toolbox you should have the ListBoxWithEvents control now and you can simply drag and drop in your form and replace the one you have. 在您的工具箱中,您现在应该拥有ListBoxWithEvents控件,您可以简单地拖放form并替换您拥有的form Since it derive from the listbox all it has is extra features. 由于它是从listbox派生的,因此它具有其他功能。 It didn't lose anything it had before. 它没有丢失以前的任何东西。

Now you need to change 2 things. 现在您需要更改2件事。 In your form select the new ListBoxWithEvents control and go in the properties events and you will find the new event called ItemAdded you can double click that and it should create an event like the following. 在您的form选择新的ListBoxWithEvents控件,然后进入属性事件,您将找到名为ItemAdded的新事件,您可以双击该事件,它应该创建一个如下所示的事件。 I have also thrown in a sample MessageBox that display all you will need. 我还抛出了一个示例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());
}

Finally in order to trigger that event you need to use the new method lst.AddItem(object); 最后,为了触发该事件,您需要使用新方法lst.AddItem(object); instead of lst.Items.Add(object); 而不是lst.Items.Add(object); so according to your sample code you need to change this : 因此,根据您的示例代码,您需要更改以下内容:

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

to this : 对此:

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

Try it and now you should have that event fire every time something is added to the list. 尝试一下,现在每次添加到列表中时,都应该触发该事件。

Since you are pretty new to programming i find it important to mention that this event will trigger on the UI thread and not the thread you created. 由于您是编程的新手,因此我发现必须提及此事件将在UI线程而不是您创建的线程上触发,这一点很重要。 This mean it behave normally like clicking on a button triggers a button_click(object sender, EventArgs e) event. 这意味着它的行为就像在单击button触发button_click(object sender, EventArgs e)事件一样。 No special thread involved whatsoever. 无需任何特殊线程。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM