Saya telah menyadari betapa seringnya seseorang perlu menulis pola kode berikut dalam kode GUI yang digerakkan oleh event, di mana
private void DoGUISwitch() {
// cruisin for a bruisin' through exception city
object1.Visible = true;
object2.Visible = false;
}
menjadi:
private void DoGUISwitch() {
if (object1.InvokeRequired) {
object1.Invoke(new MethodInvoker(() => { DoGUISwitch(); }));
} else {
object1.Visible = true;
object2.Visible = false;
}
}
Ini adalah pola canggung dalam C #, baik untuk diingat, dan untuk mengetik. Adakah yang datang dengan semacam jalan pintas atau konstruksi yang mengotomatisasi ini ke tingkat tertentu? Akan keren jika ada cara untuk melampirkan fungsi ke objek yang melakukan pemeriksaan ini tanpa harus melalui semua pekerjaan tambahan ini, seperti object1.InvokeIfNecessary.visible = true
pintasan jenis.
Jawaban sebelumnya telah membahas ketidakpraktisan dari hanya memanggil Invoke () setiap kali, dan bahkan kemudian sintaks Invoke () keduanya tidak efisien dan masih canggung untuk dihadapi.
Jadi, adakah yang tahu cara pintas?
sumber
object1.InvokeIfNecessary.Visible = true
kalimat Anda ; lihat jawaban saya yang diperbarui dan beri tahu saya apa yang Anda pikirkan.Jawaban:
Pendekatan Lee dapat disederhanakan lebih lanjut
Dan bisa disebut seperti ini
Tidak perlu melewati kontrol sebagai parameter ke delegasi. C # secara otomatis membuat penutupan .
PEMBARUAN :
Menurut beberapa poster lain
Control
dapat digeneralisasi sebagaiISynchronizeInvoke
:DonBoitnott menunjukkan bahwa tidak seperti
Control
yangISynchronizeInvoke
antarmuka membutuhkan sebuah array objek untukInvoke
metode sebagai daftar parameter untukaction
.PEMBARUAN 2
Suntingan yang disarankan oleh Mike de Klerk (lihat komentar dalam cuplikan kode 1 untuk titik sisipan):
Lihat komentar ToolmakerSteve di bawah ini untuk keprihatinan tentang saran ini.
sumber
ISynchronizeInvoke
daripada memilikiControl
? (Kudos to Jon Skeet stackoverflow.com/questions/711408/… )ISynchronizeInvoke
. Tetapi satu-satunya jenis yang berasal darinya (menurut Reflektor) adalahControl
, sehingga adavantage terbatas.while (!control.Visible) ..sleep..
. Bagi saya yang memiliki bau kode yang buruk, karena berpotensi menunda tanpa batas (mungkin bahkan loop tak terbatas dalam beberapa kasus), dalam kode yang mungkin memiliki penelepon yang tidak mengharapkan penundaan seperti itu (atau bahkan kebuntuan). IMHO, setiap penggunaanSleep
harus menjadi tanggung jawab masing-masing penelepon, ATAU harus di bungkus terpisah yang jelas ditandai sebagai konsekuensinya. IMHO, biasanya akan lebih baik untuk "gagal keras" (pengecualian, untuk menangkap selama pengujian), atau "tidak melakukan apa-apa" jika kontrolnya tidak siap. Komentar?InvokeRequired
memberitahu apakah utas panggilan berbeda dari utas yang membuat kontrol.Invoke
meneruskan aksi dari utas panggilan ke utas kontrol tempat eksekusi. Ini memastikan bahwa, sebagai contoh, pengendali event klik tidak pernah terganggu.Anda dapat menulis metode ekstensi:
Dan gunakan seperti ini:
EDIT: Seperti yang ditunjukkan Simpzon dalam komentar, Anda juga dapat mengubah tanda tangan menjadi:
sumber
Inilah formulir yang telah saya gunakan di semua kode saya.
Saya mendasarkan ini pada entri blog di sini . Saya belum mendapatkan pendekatan ini yang membuat saya gagal, jadi saya tidak melihat alasan untuk menyulitkan kode saya dengan cek
InvokeRequired
properti.Semoga ini membantu.
sumber
InvokeRequired
jika kode dapat dieksekusi sebelum kontrol ditampilkan atau Anda akan memiliki pengecualian fatal.Buat file ThreadSafeInvoke.snippet, dan kemudian Anda bisa memilih pernyataan pembaruan, klik kanan dan pilih 'Surround With ...' atau Ctrl-K + S:
sumber
Berikut ini adalah versi jawaban Lee, Oliver dan Stephan yang ditingkatkan / dikombinasikan.
Template memungkinkan untuk kode yang fleksibel dan tanpa cor yang jauh lebih mudah dibaca sementara delegasi khusus memberikan efisiensi.
sumber
Saya lebih suka menggunakan contoh tunggal metode Delegasi daripada membuat contoh baru setiap kali. Dalam kasus saya, saya digunakan untuk menampilkan kemajuan dan (info / kesalahan) pesan dari Backroundworker menyalin dan melemparkan data besar dari contoh sql. Setiap saat setelah sekitar 70000 kemajuan dan panggilan pesan formulir saya berhenti berfungsi dan menampilkan pesan baru. Ini tidak terjadi ketika saya mulai menggunakan delegasi instance global tunggal.
sumber
Pemakaian:
Kode:
sumber
Saya agak suka melakukannya sedikit berbeda, saya suka menyebut "diri saya" jika diperlukan dengan Aksi,
ini adalah pola yang berguna, IsFormClosing adalah bidang yang saya setel ke True ketika saya menutup formulir saya karena mungkin ada beberapa utas latar belakang yang masih berjalan ...
sumber
Anda tidak boleh menulis kode yang terlihat seperti ini:
Jika Anda memiliki kode yang terlihat seperti ini maka aplikasi Anda tidak aman-utas. Ini berarti bahwa Anda memiliki kode yang sudah memanggil DoGUISwitch () dari utas yang berbeda. Sudah terlambat untuk memeriksa untuk melihat apakah ada di utas yang berbeda. InvokeRequire harus dipanggil SEBELUM Anda menelepon DoGUISwitch. Anda tidak boleh mengakses metode atau properti apa pun dari utas berbeda.
Referensi: Control.InvokeRequired Property tempat Anda dapat membaca yang berikut ini:
Dalam arsitektur CPU tunggal tidak ada masalah, tetapi dalam arsitektur multi-CPU Anda dapat menyebabkan bagian dari utas UI ditugaskan ke prosesor tempat kode panggilan dijalankan ... dan jika prosesor itu berbeda dari tempat utas UI sedang berjalan maka ketika utas panggilan berakhir Windows akan berpikir bahwa utas UI telah berakhir dan akan mematikan proses aplikasi yaitu aplikasi Anda akan keluar tanpa kesalahan.
sumber
invoke()
et al sebelum kontrol diberi pegangan, tetapi IMHO tidak menjelaskan apa yang telah Anda uraikan. Inti dari semuainvoke()
omong kosong ini adalah untuk memperbarui UI dengan cara yang aman, dan saya pikir menempatkan lebih banyak instruksi dalam konteks pemblokiran akan menyebabkan kegagapan? (Ugh ... senang saya berhenti menggunakan M $ tech. Sangat rumit!)