c# Как вызвать метод “textBox” в windows forms из другого потока чтобы прокрутить в конец списка

200
11 января 2018, 19:15

Имеется "textBox" (многострочный), заполняется сообщениями из "serialPort" и при добавлении новых строк прокручивается вверх (как уже все знают). Знаю что исправляется это методами

   textBox1.SelectionStart = textBox1.Text.Length;
   textBox1.ScrollToCaret();
   textBox1.Refresh();

Но у меня многопоточность и прямое обращение к форме созданной в другом потоке "не безопасно". Для вызова метода "textBox.Text" есть специальный способ с применением "invoke" и delegate. Надеюсь что для вызова других его методов тажке есть способ, однако я так и не нашел его.

Я применил хитрость (глупость) и вызвал "прокрутку списка" по событию textBox1_TextChanged(), но тогда текст прыгает вверх и вниз как безбашенный, сперва прокручиваясь вверх по принятию новой строки, а потом вниз по событию "text changed". UPDATE: Оказалось что список скачет как бешеный во всех случаях при использовании способа textBox.Text += "something"; и постоянно печатающегося текста.

Решение этой проблемы в использовании другого способа печатать в textBox: textBox.AppendText("something");

, а если вам нужна новая строка то: textBox.AppendText(Environment.NewLine); этот метод автоматически прокручивает "textBox" в конец текста Этот метод быстрее и намного стабильнее (как я заметил).

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.IO.Ports;
using System.Threading;
namespace factyWinDBIntrf01
{
    public partial class Form1 : Form
    {
        private Thread readingThread;
        public Form1()
        {
            InitializeComponent();
            getAvailPorstList();
        }
        void getAvailPorstList()
        {
            String[] portsList = SerialPort.GetPortNames();
            selectCOMPort.Items.AddRange(portsList);
        }
        private void groupBox2_Enter(object sender, EventArgs e)
        {
        }
        private void button2_Click(object sender, EventArgs e)
        {
            try
            {
                textBox1.Text += serialPort1.ReadLine();
                textBox1.Text += "\n";
            }

            catch (TimeoutException)
            {
                textBox1.Text = "Receive Timeout";
            }
        }
        private void button4_Click(object sender, EventArgs e) 
        {
            try
            {
                if (selectCOMPort.Text == "")
                {
                    textBox1.Text = "COM Port is not selected";
                }
                else if (comboBox1.Text == "")
                {
                    textBox1.Text = "Baud rate is not set";
                }
                else
                {
                    serialPort1.PortName = selectCOMPort.Text;
                    serialPort1.BaudRate = Convert.ToInt32(comboBox1.Text);
                    serialPort1.Open();
                    progressBar1.Value = 100;
                    textBox1.Enabled = true;
                    textBox2.Enabled = true;
                    button2.Enabled = true;
                    button3.Enabled = true;
                    selectCOMPort.Enabled = false;
                    button4.Enabled = false;
                    button5.Enabled = true;
                    readingThread = new Thread(readSerial);
                    readingThread.Start();
                }
            }
            catch (UnauthorizedAccessException)
            { textBox1.Text = "Unauthorized Access"; }
        }
        private void button5_Click(object sender, EventArgs e)
        {
            readingThread.Abort();
            serialPort1.Close();
            progressBar1.Value = 0;
            textBox1.Enabled = false;
            textBox2.Enabled = false;
            button2.Enabled = false;
            selectCOMPort.Enabled = true;
            button4.Enabled = true;
            button5.Enabled = false;
        }
        private void button3_Click(object sender, EventArgs e)
        {
            serialPort1.WriteLine(textBox2.Text);
        }
        void readSerial()
        {
            while (serialPort1.IsOpen)
            {
                try
                {
                    if (serialPort1.IsOpen)
                    {
                        textBox1_TextSafe(serialPort1.ReadLine());
                        textBox1_TextSafe("\n");
                        //DOESN'T WORK FOR MULTITHREAD CODE
                        //textBox1.Text += serialPort1.ReadLine();
                        //textBox1.Text += "\n";
                    }
                }
                catch (TimeoutException)
                {
                    textBox1.Text = "Receive Timeout";
                }
                //not needed //Tread.Sleep(0);
            }
        }
        delegate void StringArgReturningVoidDelegate(string text);
        private void textBox1_TextSafe(string text)
        {
            if(textBox1.InvokeRequired)
            {
                StringArgReturningVoidDelegate d = new StringArgReturningVoidDelegate(textBox1_TextSafe);
                Invoke(d, new object[] { text });
               //-1@ NEED SOMETHING LIKE THIS I GUESS
                //textBox1.SelectionStart = textBox1.Text.Length;
               // textBox1.ScrollToCaret();
                //textBox1.Refresh();
            }
           else
            {
                textBox1.Text += text;
                //-1@ AND THIS 
                //textBox1.SelectionStart = textBox1.Text.Length;
                //textBox1.ScrollToCaret();
                //textBox1.Refresh();
            }
        }
        private void textBox1_TextChanged(object sender, EventArgs e)
        {
            //-2@ STUPID IDEA
            //textBox1.SelectionStart = textBox1.Text.Length;
            //textBox1.ScrollToCaret();
            //textBox1.Refresh();
        }
    }
}
Answer 1

Попробуйте так

textBox.Invoke(new Action(() =>{
    // делайте все, что вам нужно сделать в UI
}));
READ ALSO
Адаптация кода с Java на C# [требует правки]

Адаптация кода с Java на C# [требует правки]

Добрый вечер господа, нужна помощь человека который хорошо разбирается в Java с целью анализа имеющегося исходного кода программы, так как...

169
Что установить в Visual studio 2017 для разработки на c#?

Что установить в Visual studio 2017 для разработки на c#?

Я решил установить Visual studio 2017 enterprise и возник вопрос: где поставить галочки для разработки на c#Знаю что можно позже установить оставшийся...

165
Дата и время UWP

Дата и время UWP

Столкнулся с проблемой байдинга даты и времениИдея такая: дата выбирается в CalendarDatePicker, а время указывается в TimePicker

143
Как после события Click выполнить свой метод?

Как после события Click выполнить свой метод?

На форме расположен ToolStrip, в котором есть несколько кнопокПри нажатии на кнопку отрабатывает событие ItemClicked, затем отрабатывает метод Click конкретной...

161