При выполнении приведенного ниже кода ярлыки в форме должны отображать значения vx и vy через ярлыки xVelV и yVelV. К сожалению, оба ярлыка не отвечают во время цикла while. Однако, когда программа выходит из цикла, значения затем обновляются.

Я пробовал тот же код, определяя vx и vy как свойства с помощью методов get и set (например, метод set, устанавливающий значение vx и xVelV.text одновременно), но без изменений.

Кто-нибудь может понять, что я делаю не так?

примечание: существует g, определенный вне цикла while (например, Graphics g = panel.CreateGraphics();), который затем используется для рисования прямоугольников внутри блока while.

using System;
using System.Drawing;
using System.Windows.Forms;

namespace fff {
    class FormMain : Form {    
        // ... some code before
        private Label xVelL = new Label();
        private Label yVelL = new Label();
        // ... some code after

        public FormMain() {
            // ... some code here
            this.Controls.Add(xVelV);
            this.Controls.Add(yVelV);
            // ... some code here
        }

        public void RunG() {            
            // ... some code here
            double x = 400.0, y = 050.0, xn, yn, vx, vy, ax, ay;
            // ... some code here
            bool massOut = false;

            while (!massOut) {
                // ... some code here
                vx += ax;
                vy += ay;
                // ****** bug is here below !!! ******
                this.xVelV.Text = vx.ToString();
                this.yVelV.Text = vy.ToString();
                // ****** bug is here above !!! ******
                xn = x + vx;
                yn = y + vy;
                if (xn < 0 || xn > width || yn < 0 || yn > height) {
                    massOut = true;
                }
                else {
                    // ... some code here
                    x = xn;
                    y = yn;
                    // ... some code here
                }
            }
        }
    }
}
c#
0
ssd 27 Дек 2015 в 01:15

2 ответа

Лучший ответ

RunG () выполняется в ответ на какое-либо событие. Не уверен что, но должно быть. Это означает, что сообщение было извлечено из очереди сообщений в главном цикле сообщений программы, произошла работа с фреймворком, был вызван обработчик событий, он вызвал RunG (), а основной цикл сообщений блокируется до тех пор, пока все это не раскроется.

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

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

Вам нужно вызывать RunG () в другом потоке и Invoke () из него в поток пользовательского интерфейса периодически для обновления пользовательского интерфейса. Только поток пользовательского интерфейса может касаться объектов пользовательского интерфейса, поэтому функция Invoke () необходима.

Вот вопрос с множеством ответов об обновлении пользовательского интерфейса из потока пользовательского интерфейса:

Как обновить графический интерфейс из другого потока на C #?

3
Community 23 Май 2017 в 12:23

Это потому, что вы запускаете функцию RunG из потока пользовательского интерфейса. Это означает, что весь другой код (обрабатывающий сообщения от других элементов управления) не может работать. Вы должны вызвать выполнение этого метода, или вы можете использовать такой код:

// this code is in method originally calling RunG();
Task.Run(() => {
    RunG();
});

РЕДАКТИРОВАТЬ: Как правильно указано в комментариях, использования кода выше недостаточно. Вы также должны изменить методы, которые изменяют элементы пользовательского интерфейса, такие как this.xVelV.Text = someValue;. Вы должны вызвать этот метод:

this.xVelV.Invoke((Action)delegate() { this.xVelV.Text = someValue; });

При вызове исполняемый код выполняется в контексте потока пользовательского интерфейса этого TextBox. Без вызова любой код, работающий в другом потоке (отличный от потока пользовательского интерфейса, который создал элемент пользовательского интерфейса), вызовет исключение.

3
Pavel Pája Halbich 27 Дек 2015 в 00:36