2011-06-06 25 views
5

Şu anda kendim çizmem gereken bir kenarlık alanı olan System.Windows.Forms.ContainerControl'dan türetilen bir denetim yapıyorum. , OnPaintNonClientArea içindeDrawImageUnscaled neden WM_NCPAINT kullanıldığında yanıp sönüyor?

protected override void WndProc(ref Message m) 
{ 
    switch (m.Msg) 
    { 
    case WM_NCPAINT: 
     IntPtr hDC = NativeApi.Methods.GetWindowDC(m.HWnd); 
     if (hDC != IntPtr.Zero) 
     { 
     using (Graphics canvas = Graphics.FromHdc(hDC)) 
     { 
      if (Width > 0 && Height > 0) 
      using (PaintEventArgs e = new PaintEventArgs(canvas, new Rectangle(0, 0, Width, Height))) 
      { 
       OnPaintNonClientArea(e); 
      } 
     } 
     NativeApi.Methods.ReleaseDC(m.HWnd, hDC); 
     } 
     m.Result = IntPtr.Zero; 
     break; 
    } 
    base.WndProc(ref m); 
} 

yaptım: geçersiz kılmak için hiçbir OnPaintNonClientArea olmadığından, bu (kısalık için kaldırıldı WM_NCCALCSIZE, WM_NCHITTEST vb gibi diğer mesajların ele) gibi kendim inşa

private void OnPaintNonClientArea(PaintEventArgs e) 
{ 
    if (_ncBuffer == null) 
    { 
    _ncBuffer = new Bitmap(Width, Height); 
    } 

    using (Graphics g = Graphics.FromImage(_ncBuffer)) 
    { 
    // painting occurs here ... 
    } 
    // this causes flickering 
    e.Graphics.DrawImageUnscaled(_ncBuffer, 0, 0, Width, Height); 
} 

Leaving

protected override void WndProc(ref Message m) 
{ 
    switch (m.Msg) 
    { 
    case WM_NCPAINT: 
     using(Bitmap ncBitmap = new Bitmap(Width, Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb)) 
     { 
     using(Graphics ncGraphics = Graphics.FromImage(ncBitmap)) 
     { 
      using (PaintEventArgs e = new PaintEventArgs(ncGraphics, new Rectangle(0, 0, Width, Height))) 
      { 
      OnPaintNonClientArea(e); 
      IntPtr hDCWin = NativeApi.Methods.GetWindowDC(m.HWnd); 
      IntPtr hDCImg = ncGraphics.GetHdc(); 
      IntPtr hBmp = ncBitmap.GetHbitmap(); 
      IntPtr hBmpOld = NativeApi.Methods.SelectObject(hDCImg, hBmp); 
      Padding p = GetNonClientArea(); 
      NativeApi.Methods.ExcludeClipRect(hDCWin, p.Left, p.Top,Width- p.Right, Height-p.Bottom); 
      NativeApi.Methods.BitBlt(hDCWin, 0, 0, Width, Height, hDCImg, 0, 0,NativeApi.TernaryRasterOperations.SRCCOPY); 
      NativeApi.Methods.SelectObject(hDCImg, hBmpOld); 
      NativeApi.Methods.DeleteObject(hBmp); 
      ncGraphics.ReleaseHdc(hDCImg); 
      NativeApi.Methods.ReleaseDC(m.HWnd, hDCWin); 
      } 
     } 
     } 
     m.Result = IntPtr.Zero; 
     break; 
    } 
    base.WndProc(ref m); 
} 

Peki, nedenyapar: bakir OnPaintNonClientArea, bu titreşimi ortadan kaldırır 10 bu titremeye neden oldu mu? Tamponu çizmeden önce üzerinde çalıştığı alanı beyaz bir fırça ile siliyor gibi görünüyor. Dokümanlarda bu sorunu açıklayan hiçbir şey bulamadım. Kontrolün etrafında sadece küçük bir sınır olması çok fazla önemli değil, fakat NC alanı içinde metin görüntülenecek, böylece alan açıkça görülebiliyor ve bu nedenle titreme gerçekten görülebilir ve can sıkıcı oluyor.

İlgili sorular: Yerel GDI öğelerini doğru yapıyorum mu, yoksa şu anda göremediğim olası sorunlar var mı? Ayrıca, ncBitmap'u oluştururken, kontrol genişliğini ve yüksekliğini kullanıyorum, ancak GDI + özünürlük-bağımsız, orada herhangi bir sorun olabilir mi?

+0

Formda Double Buffering kullanmayı denediniz mi? Çift Tamponlama, bunun gibi grafik sorunları ile başa çıkmak gerekiyordu. Ayrıca, grafik nesnesini yüklemeden önce denetimin güncellenmesini durdurmak için kullanabileceğiniz SuspendLayout ve PerformLayout eşdeğerleri var mı? –

+0

Bunun için teşekkürler. Bu şeylerle uzunca bir süre uğraştım ve her türlü şeyi denedim, bir noktada fark yaratmayan formu ikiye katladım. Ben bunun zaten geçerli olduğunu sanmıyorum, çünkü ben zaten etkili bir şekilde çift-bloke yapıyorum - 'Graphics' nesnesini kullanarak tüm nesneleri boyayorum ve daha sonra 'DrawImageUnscaled' kullanarak arabelleği tarafından oluşturulan Graphics nesnesini boyamaya çalışıyorum. Graphics.FromHdc (hDC) '. Önce DrawImageUnscaled'in kendisi beyaz bir fırça kullanarak çizilecek alanı siler ve daha sonra Graphics nesnesinin içeriğini çizer. Bunun düzeltilip düzeltilemeyeceğinden emin değilim. Bilmediğim bir yaklaşım için – takrl

cevap

2

UserControl'de titremeyi önlemek için, BufferedGraphics sınıfında daha iyi şanslar yaşadım.

MSDN

bir seçenek mi?

+1

+1. Ancak, müşteri olmayan alanı boyamak için, bu, denediğim ilk yaklaşım kadar çok titremeye neden oldu. – takrl

İlgili konular