Невалидност без OnPaint

Опитвам се да направя анимация в Win Forms и опитах различен подход от извикването на Invalidate() в манипулатора timer_elapsed и след това правя неща в OnPaintHandler.

Просто рисувам директно изображение върху pictureBox, след което, когато timer_тиктака, извиквам Invalidate и след това ръчно преначертавам изображението на актуализирана позиция.

static void tmrMoving_Elapsed(object sender, EventArgs e, Train t)
{
    MainForm.playBox.Invalidate();

    g.DrawImage(t.components[i], new Rectangle(
                new Point(t.nextVagoonPositionX * 20, t.nextVagoonPositionY * 20), 
                new Size(20, 20)));
    t.nextVagoonPositionX += 1;
    t.nextPositionX = -1;
}

Имам проблем, че когато таймерът тиктака, желаното изображение понякога се изчертава, а понякога не, като 30% шанс да не нарисува (имам интервали на таймера от 1 секунда, така че мога да го видя), дори ако обектът се движи или просто намирайки се на едно и също място.

Неща, които съм пробвал:

1. Задаване на регион в Invalidate() args -> изображението беше начертано много пъти до по-старите изображения (така че не беше пребоядисано на желаното място, тъй като старите изображения останаха на местата си)

2. Извикване на Update() или Refresh() или и двете след invalidate-> Никога не е показвано изображение

3. Комбиниране на Update() или Refresh() или и двете с Invalidate(правоъгълна област) -> никога не се показва изображение

4. Задаване на DoubleBuffering true -> няма ефект

5. Игра с this.SetStyle(ControlStyles.UserPaint, true); -> няма ефект (дори не съм сигурен какво прави между другото.)


person Marek Židek    schedule 15.08.2015    source източник
comment
Изтегля се, просто не трае много дълго. Прерисувано чрез нормалните методи OnPaintBackground и OnPaint на playBox. Дали изобщо можете да виждате зависи от това колко често мигате с очи и колко отзивчива е нишката на потребителския интерфейс. Най-добрият пример за грешка в състезание с нишки, която всъщност можете да видите и не е нужно да чакате седмица. Ще трябва да спреш да го правиш погрешно.   -  person Hans Passant    schedule 15.08.2015


Отговори (1)


Не трябва директно да рисувате контроли на потребителския интерфейс извън манипулатора OnPaint. В WinAPI от "по-ниско ниво" бихте рисували само на екрана на WM_PAINT, което е това, което повдига събитието OnPaint.

Преместете своя код за рисуване (g.DrawImage(...)) от манипулатора на таймера в манипулатора OnPaint.

person Amit    schedule 15.08.2015
comment
Благодаря ви за информацията, мога ли да попитам кой е подателят, когато се обработва OnPaint? Този таймер ли е? - person Marek Židek; 15.08.2015
comment
Не, най-добре е като самата Windows система. За всички цели това се случва зад кулисите. - person Amit; 15.08.2015
comment
Изпращачът е PictureBox, причината е системата или вашият код - person TaW; 15.08.2015