2010-09-21 4 views
3

Есть ли способ отключить стирание панели без подкласса Panel и переопределить OnPaintBackground?Отключить OnPaintBackground без панели подкласса?

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

public partial class Form1 : Form 
{ 
    private Bitmap m_image; 

    public Form1() 
    { 
     InitializeComponent(); 

     panel1.Paint += new PaintEventHandler(panel1_Paint); 
     panel1.MouseMove += new MouseEventHandler(panel1_MouseMove); 

     m_image = new Bitmap(panel1.Width, panel1.Height); 
    } 

    void panel1_MouseMove(object sender, MouseEventArgs e) 
    { 
     using (Graphics g = Graphics.FromImage(m_image)) 
     { 
      g.FillEllipse(Brushes.Black, new Rectangle(e.X, e.Y, 10, 10)); 
     } 
     panel1.Invalidate(); 
    } 

    void panel1_Paint(object sender, PaintEventArgs e) 
    { 
     e.Graphics.DrawImage(m_image, 0, 0); 
    } 
} 

Это вызывает мерцание, предположительно, потому что он стирает панель на каждом цикле краски.

ответ

4

Вы можете взломать OnPaintBackground(), или вы можете взломать WndProc(). Либо нужно вывести свой собственный класс. Это тривиально, я просто не понимаю, почему вы бы этого не избежали. Дальний выстрел - SetWindowsHookEx() с крюком WH_CALLWNDPROC, слишком глупым.

+0

Часть аргументов в пользу того, что вы не хотите получать собственный класс, состоит в том, чтобы иметь возможность рисовать двойную буферизированную графику на любом объекте Panel, то есть я хочу прикрепить к какой-либо существующей панели вместо замены пользовательского элемента управления. Похоже, что нет хорошего способа сделать то, что я хочу. – WildCrustacean

+0

С WndProc вам не повезет. Многие элементы управления рисуют свой фон в WM_PAINT, а не в WM_ERASEBACKGROUND. (Потому что он мерцает). Таким образом, привязка WM_ERASEBACKGROUND будет бесполезной, и когда вы перехватите WM_PAINT, вашему коду придется рисовать фон и весь элемент управления! – Elmue

+0

Хм, нет, это панель. –

0

Просто добавьте:

panel1.BackgroundImage = m_image; 
//on panel1_Paint() function. 

Простой, не так ли?

+0

Это бесполезно. Если на панели есть ярлык или CheckBox, RadioButton или любой другой элемент управления, он все равно будет рисовать собственный (серый) фон. – Elmue

0

Использования отражения для множества защищаемого DoubleBuffered свойства:

System.Reflection.PropertyInfo aProp = 
     typeof(System.Windows.Forms.Control).GetProperty(
       "DoubleBuffered", 
       System.Reflection.BindingFlags.NonPublic | 
       System.Reflection.BindingFlags.Instance); 

aProp.SetValue(panel1, true, null); 

Вы можете также сделать его более эффективным только недействительности измененной области (это почти мерцания даже без двойной буферизации):

void panel1_MouseMove(object sender, MouseEventArgs e) 
{ 
    Rectangle r = new Rectangle(e.X, e.Y, 10, 10); 
    using (Graphics g = Graphics.FromImage(m_image)) 
    { 
     g.FillEllipse(Brushes.Black, r); 
    } 
    panel1.Invalidate(r); 
}