#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
fromOnPaint
не является хорошей идеей. Чего на самом деле вы пытаетесь достичь с помощью этого кода?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?