GDI + Paint Queue Problem

товарищи) Я ' Мы обнаружили интересное поведение метода Invalidate в многопоточных приложениях. Я надеюсь, что вы могли бы помочь мне с проблемой ...

У меня возникают проблемы при попытке сделать недействительными разные элементы управления одновременно: хотя они идентичны, один успешно перерисовывает себя, а другой - нет.

Вот пример: у меня есть форма (MysticForm) с двумя панелями (SlowRenderPanel) на нем. Каждая панель имеет таймер и с периодом 50 мс вызывается метод Invalidate (). В методе OnPaint я рисую номер текущего вызова OnPaint в центре панели. Но обратите внимание, что в OnPaint метод System.Threading.Thread.Sleep (50) вызывается для имитации процедуры рисования в течение длительного времени.

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

using System;
using System.Drawing;
using System.Windows.Forms;
using System.Runtime.InteropServices;

namespace WindowsFormsApplication1 {
    static class Program {
        [STAThread]
        static void Main() {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(new MysticForm());
        }
    }

    public class MysticForm : Form {
        public SlowRenderPanel panel1;
        public SlowRenderPanel panel2;

        public MysticForm() {
            // add 2 panels to the form
            Controls.Add(new SlowRenderPanel() { Dock = DockStyle.Left, BackColor = Color.Red, Width = ClientRectangle.Width / 2 });
            Controls.Add(new SlowRenderPanel() { Dock = DockStyle.Right, BackColor = Color.Blue, Width = ClientRectangle.Width / 2 });
        }
    }

    public class SlowRenderPanel : Panel {
        // synchronized timer
        private System.Windows.Forms.Timer timerSafe = null;
        // simple timer
        private System.Threading.Timer timerUnsafe = null;
        // OnPaint call counter
        private int counter = 0;

        // allows to use one of the above timers
        bool useUnsafeTimer = true;

        protected override void Dispose(bool disposing) {
            // active timer disposal
            (useUnsafeTimer ? timerUnsafe as IDisposable : timerSafe as IDisposable).Dispose();
            base.Dispose(disposing);
        }

        public SlowRenderPanel() {
            // anti-blink
            DoubleBuffered = true;
            // large font
            Font = new Font(Font.FontFamily, 36);

            if (useUnsafeTimer) {
                // simple timer. starts in a second. calls Invalidate() with period = 50ms
                timerUnsafe = new System.Threading.Timer(state => { Invalidate(); }, null, 1000, 50);
            } else {
                // safe timer. calls Invalidate() with period = 50ms
                timerSafe = new System.Windows.Forms.Timer() { Interval = 50, Enabled = true };
                timerSafe.Tick += (sender, e) => { Invalidate(); };
            }
        }

        protected override void OnPaint(PaintEventArgs e) {
            string text = counter++.ToString();

            // simulate large bitmap drawing
            System.Threading.Thread.Sleep(50);

            SizeF size = e.Graphics.MeasureString(text, Font);
            e.Graphics.DrawString(text, Font, Brushes.Black, new PointF(Width / 2f - size.Width / 2f, Height / 2f - size.Height / 2f));
            base.OnPaint(e);
        }

    }

}

Отладка Информация:

1) На каждой панели есть поле bool useUnsafeTime (по умолчанию установлено в true), которое позволяет использовать System.Windows.Forms.Timer (false) вместо System.Threading.Timer (true). В первом случае (System.Windows.Forms.Timer) все работает отлично. Удаление вызова System.Threading.Sleep в OnPaint также обеспечивает нормальное выполнение.

2) Установка интервала таймера 25 мс или менее предотвращает перекрашивание второй панели вообще (пока пользователь не изменяет размер формы).

3) Использование системы .Windows.Forms.Timer приводит к увеличению скорости

4) Принудительное управление для входа в контекст синхронизации (Invoke) не имеет смысла. Я имею в виду, что Invalidate (invalidateChildren = false) является «потоко-безопасным» и может иметь различное поведение в различных контекстах

. 5) Ничего интересного не найдено в сравнении IL этих двух таймеров ... Я обнаружил, что должен перечитать документацию и примеры Guice, чтобы понять, что я сделал с моим кодом. Однако, когда я смотрю на ...

я работал с GUice несколько месяцев назад, а теперь, возвращаясь к нему, я обнаружил, что должен перечитать документацию и примеры Guice, чтобы понять, что я сделал с моим кодом. [12229 Однако, когда я смотрю на AspectJ, он слишком интуитивен. Это интуитивно понятное расширение языка Java. Я чувствую, что могу сесть и сразу же написать код AspectJ.

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

Какие функции Guice существуют над AspectJ, что должно отговорить меня от отказа от Guice?

Почему бы Google не отказаться от Guice и использовать вместо него AspectJ?

наоборот Каковы особенности AspectJ, которые побудили бы меня отказаться от Guice, помимо его интуитивности?

Если мне будет позволено «плести» здесь вопрос, что препятствует слиянию языка Java с AspectJ или предоставлению аналогичного «аспекты» в будущей версии Java?

Примечание : , чтобы вызвать счастливые delete-azillas, я понимаю, что этот вопрос может быть слишком общим - но если бы я знал, какие дополнительные вопросы задать, то я бы даже не нужно спрашивать, а просто Google / BING для того, что я знаю, что я не знаю. Как видите, мои знания Guice настолько сильно ухудшились, что я даже не узнаю свой собственный почерк .

7
задан Blessed Geek 19 August 2010 в 20:39
поделиться

3 ответа

Как говорит Питер, Guice и AspectJ - совершенно разные вещи. Guice выполняет внедрение зависимостей, избавляя от необходимости писать на заводе, делая код гибким и легким для тестирования, и добавляя такие полезные вещи, как области видимости. Это также позволяет очень простой и легкий способ выполнения АОП с помощью перехвата методов (с программной конфигурацией перехватываемых методов, а не с помощью DSL). По сути, это просто еще один бонус, который он предоставляет, а не его основная цель.

Что касается того, почему AspectJ не объединен с Java ... Я не думаю, что многие люди захотят, чтобы это произошло. АОП - мощный, но опасный способ. Хотя он, безусловно, отлично подходит для некоторых применений и значительно упрощает код в этих случаях, при чрезмерном использовании он может значительно затруднить понимание того, что происходит в программе.

19
ответ дан 6 December 2019 в 06:23
поделиться

Spring построен на внедрении зависимостей и аспектно-ориентированном программировании.

Guice - это двигатель с впрыском зависимостей.

AspectJ - это аспектно-ориентированный движок.

Видите разницу? Guice и AspectJ будут дополнять друг друга; У весны уже есть и то, и другое.

Следует отметить, что Spring поддерживает собственный АОП на основе перехватчика, который не требует манипуляции с байтовым кодом, в дополнение к AspectJ.

2
ответ дан 6 December 2019 в 06:23
поделиться

According to me AspectJ and Guice do different things.

Guice injects dependencies and AspectJ deals with crosscutting concerns.

If you use spring then indeed there is less value in using Guice since there is too much overlap and then the symbiosis of Spring/AspectJ is a compelling solution.

I personqlly like guice better for non-spring projects because of its lighter weight.

7
ответ дан 6 December 2019 в 06:23
поделиться
Другие вопросы по тегам:

Похожие вопросы: