Как реализован Invalidate ???
От: Cynic Россия  
Дата: 09.05.08 22:15
Оценка:
Писал тут код для реализации индикатора хода процесса. Индикатор поддерживает вращение вокруг оси. Для реализации вращения написал отдельный метод запускаемый конструктором класса в отдельном потоке. Назначение этого метода определённое количество раз в секунду вызывать метод Invalidate(). Выглядит этот метод примерно так:
    //...время последнего вызова Invalidate()...
    private long _lastInvalidateTick = 0;

    protected override void OnInvalidated(InvalidateEventArgs e)
    {
        base.OnInvalidated(e);
        _lastInvalidateTick = DateTime.Now.Ticks;
    }

    void ReDrawBar()
    {
        //...количество выполнений метода в секунду...
        int timesPerSecond = 50;

        while (_rotateThread.ThreadState == ThreadState.Running)
        {
            if (_lastInvalidateTick == 0)
            {
                Invalidate();
                continue;
            }

            //...время прошедшее после последнего вызова Invalidate()...
            float elapsedTime = (DateTime.Now.Ticks - _lastInvalidateTick) / 10000000f;

            if (elapsedTime > 1 / (timesPerSecond * 2f))
            {
                _currentRotateAngle += _rotateSpeed * elapsedTime;
                Invalidate();
            }
            Thread.Sleep(1000 / timesPerSecond);
        }
    }

Прокомментирую.
    if (elapsedTime > 1 / (timesPerSecond * 2f))

Эта условие не вызывает метод Invalidate() если он был вызван "недавно". То есть если метод выполняется 50 раз в секунду(каждые 0,02 секунды), а с момента последнего выполнения Invalidate() прошло времени меньше чем 0,02 секунды, то Invalidate() повторно не вызывается, т.к. в этом просто нет смысла, потому что индикатор и так был не давно перерисован.
И вроде все работает как надо, однако когда начал тестировать заметил одну особенность. Если метод вызывал Invalidate() 50 раз в секунду, то OnPaint() вызывался только 10-12 раз в секунду! Если количество вызовов метода увеличивалось до 100 раз в секунду ситуация не менялась, OnPaint() упорно вызывался с таким же промежутком. Это навело меня на мысль, что реализация Invalidate() специально вызывает OnPaint() не очень часто
Поэтому вопросы такие: Сколько раз в секунду вызывается OnPaint и, что этим управляет? Возможна ли ситуация, и когда, что OnPaint вызывается чаше чем в моем случае? Как повлиять на количество вызовов OnPaint за промежуток времени
:)
Re: Как реализован Invalidate ???
От: Cynic Россия  
Дата: 09.05.08 22:35
Оценка:
Кстати сейчас провёл измерения и увидел, что если Invalidate() вызывается 100 раз в секунду, то OnPaint от 13 до 76 раз. А если Invalidate() вызывается 10 раз в секунду, то OnPaint от 5 до 9 раз В любом случае при разных значениях, OnPaint ни когда не вызывался больше раз чем Invalidate()!
Я помню, что Invalidate() запросы накапливаются и обрабатываются все разом. Вот только как мне управлять количеством вызовов OnPaint? Разместить в OnPaint код который будет вырубать все попытки вызвать метод больше определённого количества раз в секунду? Но в результате могут появиться рывки в движении индикатора. Может быть есть встроенные средства управления этим процессом?
И как вы думаете какое количество перерисовок индикатора в секунду оптимально? Не забываем, что он вращается, причём скорость вращения можно задавать разную!
:)
Re[2]: Как реализован Invalidate ???
От: Andy77 Ниоткуда  
Дата: 09.05.08 23:56
Оценка: 6 (1)
Здравствуйте, Cynic, Вы писали:

C> Я помню, что Invalidate() запросы накапливаются и обрабатываются все разом. Вот только как мне управлять количеством вызовов OnPaint?


Control.Refresh();
Re[3]: Как реализован Invalidate ???
От: Аноним  
Дата: 10.05.08 10:38
Оценка:
Здравствуйте, Andy77, Вы писали:

C>> Я помню, что Invalidate() запросы накапливаются и обрабатываются все разом. Вот только как мне управлять количеством вызовов OnPaint?

A>Control.Refresh();

Если я вызову Invalidate(), например 100 раз, сколько раз будет вызван OnPaint()? От чего это зависит? Понятно, что перемещении контрола он будет перерисовываться чаще, а если контрол не подвижен, от чего будет зависеть количество вызовов OnPaint()?
Re[4]: Как реализован Invalidate ???
От: MaximSL  
Дата: 10.05.08 17:56
Оценка:
Зависит от того, насколько загружен Ваш поток. По крайней мере для Win32 GUI это верно (не знаю как для дотнета). Вообще, если Вам нужно точно обновлять контрол в данный момент времени пользуйтесь RedrawWindow (какой-то аналог этой функции в дотнет-мире должен быть). Очень хорошо о том как работает рисование и формируется WM_PAINT у Рихтера написано.
Re[4]: Как реализован Invalidate ???
От: TK Лес кывт.рф
Дата: 10.05.08 20:15
Оценка:
Здравствуйте, Аноним, Вы писали:

А> Если я вызову Invalidate(), например 100 раз, сколько раз будет вызван OnPaint()? От чего это зависит? Понятно, что перемещении контрола он будет перерисовываться чаще, а если контрол не подвижен, от чего будет зависеть количество вызовов OnPaint()?


Сообщение отрисовки WM_PAINT как таковое не является "настоящим" сообщением это фактически флажок говорщий о том, что у окна есть невалидные области. Поэтому, повторный вызов Invalidate не приведет к "двух кратному" вызову OnPaint. Данное сообщение обладает низким приоритетом — это означает, что обработано оно будет в "последнюю" очередь.
Если у Вас нет паранойи, то это еще не значит, что они за Вами не следят.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.