Saya memiliki kontrol yang harus saya modifikasi. Saya ingin benar-benar mencegahnya menggambar ulang sementara saya melakukan itu - SuspendLayout dan ResumeLayout tidak cukup. Bagaimana cara menangguhkan lukisan untuk kontrol dan anak-anaknya?
184
Jawaban:
Di pekerjaan saya sebelumnya, kami berjuang untuk mendapatkan aplikasi UI kami yang kaya untuk melukis secara instan dan lancar. Kami menggunakan kontrol .Net, kontrol kustom, dan kontrol devexpress standar.
Setelah banyak menggunakan googling dan reflektor saya menemukan pesan win32 WM_SETREDRAW. Ini benar-benar berhenti menggambar kontrol sementara Anda memperbaruinya dan dapat diterapkan, IIRC ke panel induk / yang mengandung.
Ini adalah kelas yang sangat sangat sederhana yang menunjukkan cara menggunakan pesan ini:
Ada diskusi yang lebih lengkap tentang ini - google untuk C # dan WM_SETREDRAW, mis
C # Jitter
Tata Letak yang Menangguhkan
Dan kepada siapa yang berkepentingan, ini adalah contoh serupa di VB:
sumber
Control
kelas dasar untuk semua kontrol WinForms sudah melakukan untukBeginUpdate
danEndUpdate
metode. Mengirim pesan sendiri tidak lebih baik daripada menggunakan metode-metode itu untuk melakukan pekerjaan berat untuk Anda, dan tentu saja tidak dapat menghasilkan hasil yang berbeda.Control.Handle
akan memaksa pegangan jendela dibuat dan dapat memengaruhi kinerja. Misalnya jika Anda memindahkan kontrol pada formulir sebelum ditampilkan, jika Anda memanggil iniSuspendDrawing
sebelumnya, gerakan Anda akan lebih lambat. Mungkin harusif (!parent.IsHandleCreated) return
diperiksa di kedua metode.Berikut ini adalah solusi yang sama dari ng5000 tetapi tidak menggunakan P / Invoke.
sumber
Message
dan di manaNativeWindow
; mencari dokumentasi untuk kelas bernamaMessage
tidak benar-benar menghibur.Invalidate()
tidak bekerja sebagusRefresh()
kecuali diikuti oleh satu lagi pula.Saya biasanya menggunakan versi modifikasi dari jawaban ngLink .
Ini memungkinkan penangguhan / melanjutkan panggilan untuk disarangkan. Anda harus memastikan untuk mencocokkan masing
SuspendDrawing
- masing dengan aResumeDrawing
. Oleh karena itu, mungkin bukan ide yang baik untuk mempublikasikannya.sumber
SuspendDrawing(); try { DrawSomething(); } finally { ResumeDrawing(); }
. Pilihan lain adalah untuk mengimplementasikan ini diIDisposable
kelas dan untuk melampirkan bagian gambar di-using
pernyataan. Pegangan akan diteruskan ke konstruktor, yang akan menangguhkan gambar.DllImport
declarewParam
sebagaibool
?Untuk membantu dengan tidak lupa mengaktifkan kembali gambar:
pemakaian:
sumber
action()
melempar pengecualian? (Gunakan percobaan / akhirnya)Solusi yang bagus tanpa menggunakan interop:
Seperti biasa, cukup aktifkan DoubleBuffered = true pada CustomControl Anda. Kemudian, jika Anda memiliki wadah seperti FlowLayoutPanel atau TableLayoutPanel, dapatkan kelas dari masing-masing jenis ini dan di konstruktor, aktifkan buffering ganda. Sekarang, cukup gunakan Wadah asal Anda dan bukan Wadah Windows.
sumber
Berdasarkan jawaban ng5000, saya suka menggunakan ekstensi ini:
Menggunakan:
sumber
Berikut ini adalah kombinasi dari ceztko's dan ng5000's untuk menghadirkan versi ekstensi VB yang tidak menggunakan pinvoke
sumber
Saya tahu ini adalah pertanyaan lama, sudah dijawab, tetapi inilah pendapat saya tentang ini; Saya refactored penangguhan pembaruan menjadi IDisposable - dengan cara itu saya bisa melampirkan pernyataan yang ingin saya jalankan dalam
using
pernyataan.sumber
Ini bahkan lebih sederhana, dan mungkin hacky - karena saya dapat melihat banyak otot GDI di utas ini , dan jelas hanya cocok untuk skenario tertentu. YMMV
Dalam skenario saya, saya menggunakan apa yang akan saya sebut sebagai UserControl "Induk" - dan selama
Load
acara tersebut, saya cukup menghapus kontrol-yang-akan-dimanipulasi dari.Controls
koleksi Induk , dan IndukOnPaint
mengurus sepenuhnya melukis anak itu kontrol dengan cara khusus apa pun .. sepenuhnya mengambil kemampuan melukis anak offline.Sekarang, saya menyerahkan rutinitas cat anak saya ke metode ekstensi berdasarkan konsep ini dari Mike Gold untuk mencetak formulir windows .
Di sini saya membutuhkan sub-set label untuk merender tegak lurus terhadap tata letak:
Kemudian, saya membebaskan kontrol anak dari dicat, dengan kode ini di
ParentUserControl.Load
pengendali acara:Kemudian, di ParentUserControl yang sama, kami melukis kontrol-untuk-dimanipulasi dari bawah ke atas:
Setelah Anda meng-host ParentUserControl di suatu tempat, misalnya Formulir Windows - Saya menemukan bahwa Visual Studio 2015 saya merender formulir dengan benar pada Waktu Desain serta runtime:
Sekarang, karena manipulasi khusus saya memutar kontrol anak 90 derajat, saya yakin semua hot spot dan interaktivitas telah dihancurkan di wilayah itu - tetapi, masalah yang saya pecahkan adalah semua untuk label paket yang perlu melihat dulu dan mencetak, yang bekerja dengan baik untuk saya.
Jika ada cara untuk memperkenalkan kembali hot spot dan kontrol-ke kontrol yatim sengaja saya - saya ingin belajar tentang itu suatu hari nanti (bukan untuk skenario ini, tentu saja, tapi .. hanya untuk belajar). Tentu saja, WPF mendukung kegilaan OOTB .. tapi .. hei .. WinForms masih sangat menyenangkan, oke?
sumber
Atau cukup gunakan
Control.SuspendLayout()
danControl.ResumeLayout()
.sumber