Аннулирование всех элементов управления в winform приводит к бесконечным вызовам метода OnPaint

#c# #winforms

#c# #winforms

Вопрос:

У меня есть два расширенных элемента управления. Вызывается первый LiveControl , который наследуется от PictureBox которого имеет изменение размера, поворот, перемещение,… Методы. Вызывается второй DrawPanel , который наследуется от Panel которого и должен быть родительским в течение нескольких LiveControl секунд.

Я сделал несколько вещей, чтобы уменьшить фильтрацию, а также оставлять следы при LiveControl перемещении одного над другим. и, наконец, я добился этого даже лучше, чем ожидал, с помощью следующих кодов в LiveControl :

 MouseUp  = (s, e) =>
{
    foreach (Control c in Parent.Controls.OfType<LiveControl>())
        c.Refresh();
};
MouseMove  = (s, e) =>
{
    if (e.Button == MouseButtons.Left)
    {
        Control x = (Control)s;
        x.SuspendLayout();
        x.Location = new Point(x.Left   e.X - cur.X, x.Top   e.Y - cur.Y);
        x.ResumeLayout();
        foreach (Control c in Parent.Controls.OfType<LiveControl>())
            c.Update();
    }
};

protected override void OnPaint(PaintEventArgs e)
{
    base.OnPaint(e);
    foreach (Control c in Parent.Controls.OfType<LiveControl>())                
        c.Invalidate();                    
}
  

Но проблема в том, что, как и в приведенном выше коде, каждый LiveControl ‘s OnPaint делает недействительными все LiveControl s, это вызывает бесконечные вызовы OnPaint , которые вызывают проблемы для других элементов управления в форме (они работают очень медленно с задержками).

Чтобы решить эту проблему, я отредактировал код OnPaint следующим образом:

 protected override void OnPaint(PaintEventArgs e)
{
    base.OnPaint(e);
    if (!((DrawPanel)Parent).Invalidating)
    {
        ((DrawPanel)Parent).Invalidating = true;
        ((DrawPanel)Parent).InvalidatedCount = 0;
        foreach (Control c in Parent.Controls.OfType<LiveControl>())                
            c.Invalidate();            
    }
    else
    {
        ((DrawPanel)Parent).InvalidatedCount  ;
        if (((DrawPanel)Parent).InvalidatedCount == ((DrawPanel)Parent).Controls.OfType<LiveControl>().Count())
        { 
            ((DrawPanel)Parent).InvalidatedCount = 0; ((DrawPanel)Parent).Invalidating = false;  
        }
    }
}
  

Но OnPaint метод все еще вызывается без остановки.
У кого-нибудь есть идеи, как это решить?

Комментарии:

1. downvoter, не могли бы вы сказать, почему?

2. попробуйте отключить событие рисования в событии OnPaint и после завершения задачи снова зарегистрировать его в элементе управления.. это может помочь вам преодолеть бесконечный цикл

3. @NiranjanKala если я отсоединю событие OnPaint, Invalidate() это не принесет никакой пользы.

4. Поскольку Invalidate вызывает Paint , вызов Invalidate from OnPaint не является хорошей идеей. Чего на самом деле вы пытаетесь достичь с помощью этого кода?

5. Не мое мнение, но наличие очевидного бесконечного цикла свидетельствует об отсутствии исследований. — Вызов Invalidate в Paint — это бесконечный цикл. Точка.

Ответ №1:

Invalidate триггеры Paint . Вызов Invalidate Paint — это бесконечный цикл. Не делайте этого!

Мерцание исчезнет, если все элементы управления, которые его отображают, DoubleBuffering включены. Обратите внимание, что для включения DoublBuffering вам может потребоваться подкласс некоторых из них, например Panels , FlowLayoutPanels или DGVs .. Фактически он только Form предоставляет его и включен только PictureBox по умолчанию.

Вам также необходимо убедиться, что все ненужное Invalidates удалено. — Обычно вам нужно Invalidate только тогда, когда изменились данные, необходимые для рисования. Я вообще не вижу никакого рисунка в вашем коде. В противном случае вам иногда может потребоваться вызвать Refresh , чтобы устранить разрывы, то есть «хвосты» или «следы».

Ответ №2:

Я бы вообще не занимался OnPaint. Если вы хотите создать пользовательский paint, сделайте это в событии Paint.

Вы никогда не должны вызывать Invalidate() в ситуации обновления paint. Если у вас возникли проблемы с мерцанием, пытались ли вы установить значение DoubleBuffered равным true для ваших пользовательских элементов управления и контейнера?

Если вы аннулируете DrawPanel, вызвав DrawPanel .Invalidate() для одного переопределения вызывается флаг bool invalidateChildren . Вы пытались установить для этого значение true?

Надеюсь, это поможет.

Комментарии:

1. Я пробовал DoubleBuffered , это ухудшает результат. оставляя следы по всем другим элементам управления. DrawPanel.Invalidate() , с invalidateChildren установленным значением true делает то же самое, что делает недействительными все дочерние элементы, а также делает недействительным родительский элемент. Я попробую разобраться с этим в Paint event, чтобы посмотреть, что произойдет.

2. @AshkanMobayenKhiabani: Тогда я думаю, что у вас серьезные проблемы где-то еще. Я делал то, что вы делаете много раз, без каких-либо проблем, просто позволяя Windows обрабатывать paint, аннулировать и т. Д. Вместо того, чтобы выводить из Panel , вы пытались выводить из UserControl , и, возможно, вы могли бы также поместить свой PictureBox-derive в UserControl?