Я создал форму, которая перемещается по экрану влево, но все компоненты формы пусты.
Я поместил код для движения в комментарии, и все было хорошо, поэтому проблема в моем коде движения, но я не знаю, в чем проблема.
System.Threading.Thread thread;
private void Form1_Load(object sender, EventArgs e)
{
thread = new System.Threading.Thread(loop);
thread.Start();
}
void loop()
{
this.BeginInvoke((Action)delegate () {
int x = 0;
int y = 0;
int MoveRate = 1;
Point TopLeft = this.Location;
Point TopRight = new Point (this.Location.X + this.Width, this.Location.Y);
while (true)
{
x = x + MoveRate;
this.Location = new Point(x, 150);
System.Threading.Thread.Sleep(10);
}
});
}
Это должно привести к перемещению формы влево, однако компоненты формы остаются пустыми.





Давайте посмотрим на метод loop():
void loop()
{
this.BeginInvoke((Action)delegate () {
int x = 0;
int y = 0;
int MoveRate = 1;
Point TopLeft = this.Location;
Point TopRight = new Point (this.Location.X + this.Width, this.Location.Y);
while (true)
{
x = x + MoveRate;
this.Location = new Point(x, 150);
System.Threading.Thread.Sleep(10);
}
});
}
Этот код немедленно вызывает делегата в основном потоке пользовательского интерфейса. Делегат запускает цикл while(true), который никогда не завершается. Как только цикл начинает выполняться, поток пользовательского интерфейса полностью закрывается без всякой надежды когда-либо отвечать на другие сообщения о событиях, включая события рисования.
Попробуйте вместо этого:
void loop()
{
int x = 0;
int MoveRate = 1;
while(true)
{
x += MoveRate;
this.BeginInvoke((Action)delegate () { this.Location = new Point(x, 150); });
System.Threading.Thread.Sleep(16);
}
}
Это все тот же код (за исключением того, что ничего не делало), но теперь он организован так, что делегат вызывается внутри цикла. Поток пользовательского интерфейса блокируется только на короткое время, а затем управление возвращается обратно потоку цикла, который на некоторое время переходит в спящий режим, прежде чем снова беспокоить пользовательский интерфейс. Вызов даже достаточно прост, я смог переписать его как одну строку.
Заметьте, я также увеличил время сна, потому что это по-прежнему дает вам 60 кадров в секунду.
Вариант того же процесса Async для тестирования чего-то другого.
(Основная причина, по которой ваш поток работает не так, как ожидалось, уже объяснялась. Если вы используете поток, а затем вызываете поток пользовательского интерфейса в закрытом цикле, это более или менее похоже на то, чтобы ваш код вообще не запускался в другом потоке : Форма не успевает обновлять себя или свои элементы управления).
Этот метод добавляет завершение к процедуре прокрутки, когда форма прокручивается за пределы текущего экрана. Когда это условие выполнено, цикл while завершается, и задача завершается, перемещая форму в центр экрана.
Задача запускается в событии Shown. Я думаю, что это более уместно, чем мероприятие Load (Форма готова к представлению здесь).
Обратите внимание, что ни эта задача, ни поток не добавляют никаких проверок для события Form.FormClosing, чтобы отменить асинхронную процедуру: если форма закрывается во время прокрутки, у вас, скорее всего, будет исключение (форма была удалена, поэтому больше нет ручка).
private async Task Scroller(int ScreenWidth)
{
int x = 0;
int MoveRate = 2;
while (true)
{
x += MoveRate;
this.BeginInvoke(new MethodInvoker(() => { this.Location = new Point(x, 150);}));
await Task.Delay(10);
if (x > ScreenWidth) break;
};
}
private async void Form_Shown(object sender, EventArgs e)
{
int ScreenWidth = Screen.FromHandle(this.Handle).Bounds.Width;
await this.Scroller(ScreenWidth);
this.Location = new Point((ScreenWidth - this.Width) / 2 , 150);
}