Я создал проект на C #, приложение WinForms с фоновым классом. Класс приложения WinForms содержит одну точку и рисует ее каждый раз, когда вы вызываете метод «Refresh ()». Нажав на пробел, вы запустите фоновый класс. Фоновый класс предоставляет метод «run ()», который этот метод вызывает метод вычисления определенное количество раз (в то время как цикл). Затем метод вычисления выполняет некоторые вычисления и добавляет результаты в стек, а затем запускает таймер. Этот таймер содержит метод рисования, который берет данные из стека и сообщает Форме печатать кружок для каждой записи в стеке. (Это довольно запутанно, чтобы описать код ниже и должно быть легко понять)
Теперь у меня возникла довольно странная проблема, которую я не понимаю: (см. Пример кода ниже)
В фоновом классе, когда цикл while вызывает вычисление, вычисление будет выполнено, но время не будет выполнять метод draw. Но когда вы закомментируете начало и конец цикла while и вместо этого нажимаете пробел вручную несколько раз, все работает нормально. Почему код работает без цикла и нажимает несколько раз вручную, но не с циклом while? И как я могу это исправить, чтобы заставить его работать с циклом?
Действия по воспроизведению проблемы:
Создайте новое приложение WinForms в Visual Studio, замените Form1.cs приведенным ниже кодом и создайте класс BackgroundRunner.cs с приведенным ниже кодом.
Затем просто запустите проект и нажмите пробел, чтобы запустить фоновый класс.
Чтобы получить работающий код:
Просто закомментируйте начало и конец цикла while и несколько раз нажмите пробел вручную. (движение по кругу)
Дополнительно:
Да, в этом разбитом примере выглядит странно создавать два отдельных класса и таймер форм, но во всем проекте мне нужно, чтобы он работал таким образом.
Заранее спасибо.
Я уже погуглил и нашел решения, такие как таймер и пользовательский интерфейс, которые должны быть в одном потоке и т. Д. Но я думаю, что оба находятся в одном потоке, потому что он работает без цикла.
Это класс Form1.cs:
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;
namespace TestApp
{
public partial class Form1 : Form
{
private Point p;
private BackgroundRunner runner;
private int count = 0;
private int max = 10;
public Form1() {
InitializeComponent();
p = new Point(0, 0);
runner = new BackgroundRunner(this);
}
private void Form1_Load(object sender, EventArgs e) {
}
//Method to refresh the form (draws the single point)
override
protected void OnPaint(PaintEventArgs e) {
drawPoint(p, e.Graphics);
}
//Method to draw a point
private void drawPoint(Point p, Graphics g) {
Brush b = new SolidBrush(Color.Black);
g.FillEllipse(b, p.X, p.Y, 10, 10);
}
//when you press the space bar the runner will start
override
protected void OnKeyDown(KeyEventArgs e) {
if(e.KeyValue == 32) {
runner.run();
}
}
public int getCount() {
return count;
}
public int getMax() {
return max;
}
//sets point, refreshes the form and increases the count
public void setPoint(Point pnew) {
p = pnew;
Refresh();
count++;
}
}
}
А это класс BackgroundRunner.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace TestApp
{
class BackgroundRunner
{
private Form1 form;
private System.Windows.Forms.Timer timer;
private Stack<int> test;
private int max;
private int count;
public BackgroundRunner(Form1 formtemp) {
form = formtemp;
timer = new System.Windows.Forms.Timer();
timer.Interval = 100;
timer.Tick += drawMovement;
}
public void run() {
count = form.getCount();
max = form.getMax();
//Here happens the strange stuff:
//If you comment out the while loop start and end
//and press manually the space bar the circle will move
//from right to left an up to down.
//But if you use the while loop nothing will happen
//and the "drawMovement" Method will never be executed,
//because the message inside will never be written...
Console.WriteLine("Count: " + count + " Max: " + max);
while (count < max) {
Console.WriteLine("Calc Move");
calculateMovement();
count = form.getCount();
max = form.getMax();
Thread.Sleep(50);
}
}
//Just a method that adds data to the stack and then start the timer
private void calculateMovement() {
test = new Stack<int>(5);
test.Push(10);
test.Push(20);
test.Push(30);
test.Push(40);
test.Push(50);
timer.Start();
}
//Method that goes through the stack and updates
//the forms point incl refresh
private void drawMovement(object o, EventArgs e) {
Console.WriteLine("Draw Move");
if (test.Count <= 0) {
timer.Stop();
return;
}
int x = test.Pop();
int y = count;
form.setPoint(new System.Drawing.Point(x, y));
}
}
}