SAYA TAHU pasti ada cara untuk melakukan ini (dan saya menemukan cara untuk melakukannya dengan rapi). Solusi Sheng persis seperti yang saya pikirkan sebagai solusi sementara, tetapi setelah seorang teman menunjukkan bahwa Form
kelas tersebut pada akhirnya diwarisi dari sebuah abstract
kelas, kami HARUS menyelesaikannya. Jika mereka bisa, kita bisa.
Kami beralih dari kode ini ke masalah
Form1 : Form
Masalah
public class Form1 : BaseForm
...
public abstract class BaseForm : Form
Di sinilah pertanyaan awal mulai dimainkan. Seperti yang dikatakan sebelumnya, seorang teman menunjukkan bahwa System.Windows.Forms.Form
mengimplementasikan kelas dasar yang abstrak. Kami dapat menemukan ...
Bukti solusi yang lebih baik
Dari sini, kami mengetahui bahwa mungkin saja desainer menampilkan kelas yang menerapkan kelas abstrak dasar, hanya saja tidak dapat menunjukkan kelas desainer yang segera menerapkan kelas abstrak dasar. Harus ada maksimal 5 peralihan, tetapi kami menguji 1 lapisan abstraksi dan awalnya menemukan solusi ini.
Solusi Awal
public class Form1 : MiddleClass
...
public class MiddleClass : BaseForm
...
public abstract class BaseForm : Form
...
Ini benar-benar berfungsi dan perancang membuatnya baik-baik saja, masalah terpecahkan .... kecuali Anda memiliki tingkat warisan tambahan dalam aplikasi produksi Anda yang hanya diperlukan karena ketidakcukupan dalam perancang winforms!
Ini bukan solusi pasti 100% tetapi cukup bagus. Pada dasarnya Anda menggunakan #if DEBUG
solusi yang bagus.
Solusi yang Baik
Form1.cs
#if DEBUG
public class Form1 : MiddleClass
#else
public class Form1 : BaseForm
#endif
...
MiddleClass.cs
public class MiddleClass : BaseForm
...
BaseForm.cs
public abstract class BaseForm : Form
...
Yang dilakukannya hanyalah menggunakan solusi yang diuraikan dalam "solusi awal", jika berada dalam mode debug. Idenya adalah Anda tidak akan pernah merilis mode produksi melalui build debug dan Anda akan selalu mendesain dalam mode debug.
Desainer akan selalu berjalan melawan kode yang dibangun dalam mode saat ini, jadi Anda tidak dapat menggunakan desainer dalam mode rilis. Namun, selama Anda mendesain dalam mode debug dan melepaskan kode bawaan dalam mode rilis, Anda siap melakukannya.
Satu-satunya solusi pasti adalah jika Anda dapat menguji mode desain melalui arahan preprocessor.
@smelch, Ada solusi yang lebih baik, tanpa harus membuat kontrol tengah, bahkan untuk debug.
Apa yang kita mau
Pertama, mari kita definisikan kelas terakhir dan kelas abstrak dasar.
Sekarang yang kita butuhkan hanyalah penyedia Deskripsi .
Akhirnya kita hanya menerapkan atribut TypeDescriptionProvider ke kontrol Abastract.
Dan itu dia. Tidak diperlukan kontrol tengah.
Dan kelas penyedia dapat diterapkan ke sebanyak mungkin basis Abstrak yang kita inginkan dalam solusi yang sama.
* EDIT * Juga yang berikut ini diperlukan di app.config
Terima kasih @ user3057544 untuk sarannya.
sumber
TypeDescriptionProvider
@Smelch, terima kasih atas jawaban yang membantu, karena saya mengalami masalah yang sama baru-baru ini.
Berikut adalah perubahan kecil pada posting Anda untuk mencegah peringatan kompilasi (dengan meletakkan kelas dasar dalam
#if DEBUG
arahan pra-prosesor):sumber
Saya memiliki masalah serupa tetapi menemukan cara untuk merefaktor berbagai hal untuk menggunakan antarmuka sebagai pengganti kelas dasar abstrak:
Ini mungkin tidak dapat diterapkan pada setiap situasi, tetapi jika memungkinkan akan menghasilkan solusi yang lebih bersih daripada kompilasi bersyarat.
sumber
UserControl
properti ke antarmuka dan merujuknya kapan pun saya perlu mengaksesnya secara langsung. Dalam implementasi antarmuka saya, saya memperluas UserControl dan menyetelUserControl
properti kethis
Saya menggunakan solusi dalam jawaban ini untuk pertanyaan lain, yang menautkan artikel ini . Artikel ini merekomendasikan penggunaan
TypeDescriptionProvider
implementasi kustom dan konkret dari kelas abstrak. Perancang akan menanyakan penyedia khusus jenis yang akan digunakan, dan kode Anda dapat mengembalikan kelas konkret sehingga perancang senang sementara Anda memiliki kendali penuh atas bagaimana kelas abstrak muncul sebagai kelas konkret.Pembaruan: Saya menyertakan sampel kode yang terdokumentasi dalam jawaban saya untuk pertanyaan lain itu. Kode di sana berfungsi, tetapi terkadang saya harus melalui siklus bersih / bangun seperti yang tercantum dalam jawaban saya untuk membuatnya berfungsi.
sumber
Saya punya beberapa tip untuk orang yang mengatakan
TypeDescriptionProvider
oleh Juan Carlos Diaz tidak berfungsi dan juga tidak menyukai kompilasi bersyarat:Pertama-tama, Anda mungkin harus me - restart Visual Studio agar perubahan dalam kode Anda berfungsi di desainer formulir (saya harus, membangun kembali sederhana tidak berfungsi - atau tidak setiap waktu).
Saya akan menyajikan solusi saya dari masalah ini untuk kasus Bentuk dasar abstrak. Katakanlah Anda memiliki
BaseForm
kelas dan Anda ingin formulir apa pun yang didasarkan padanya dapat dirancang (ini akan menjadiForm1
). TheTypeDescriptionProvider
sebagaimana yang disampaikan oleh Juan Carlos Diaz tidak bekerja untuk saya juga. Inilah cara saya membuatnya bekerja, dengan menggabungkannya dengan solusi MiddleClass (oleh smelch), tetapi tanpa#if DEBUG
kompilasi bersyarat dan dengan beberapa koreksi:Perhatikan atribut pada kelas BaseForm. Kemudian Anda hanya perlu mendeklarasikan
TypeDescriptionProvider
dan dua kelas menengah , tetapi jangan khawatir, mereka tidak terlihat dan tidak relevan bagi pengembang Form1 . Yang pertama mengimplementasikan anggota abstrak (dan membuat kelas dasar non abstrak). Yang kedua kosong - itu hanya diperlukan untuk desainer formulir VS untuk bekerja. Kemudian Anda menugaskan kelas menengah kedua keTypeDescriptionProvider
dariBaseForm
. Tidak ada kompilasi bersyarat.Saya mengalami dua masalah lagi:
Masalah pertama (Anda mungkin tidak memilikinya karena itu adalah sesuatu yang menghantui saya dalam proyek saya di beberapa tempat lain dan biasanya menghasilkan pengecualian "Tidak dapat mengubah tipe X ke tipe X"). Saya menyelesaikannya
TypeDescriptionProvider
dengan membandingkan nama tipe (FullName) daripada membandingkan tipe (lihat di bawah).Masalah kedua. Saya tidak benar-benar tahu mengapa kontrol formulir dasar tidak dapat dirancang di kelas Form1 dan posisinya hilang setelah diubah ukurannya, tetapi saya telah mengatasinya (bukan solusi yang bagus - jika Anda tahu lebih baik, silakan tulis). Saya hanya memindahkan tombol BaseForm secara manual (yang seharusnya berada di pojok kanan bawah) ke posisi yang benar dalam metode yang dipanggil secara asinkron dari acara Muat BaseForm:
BeginInvoke(new Action(CorrectLayout));
Kelas dasar saya hanya memiliki tombol "OK" dan "Batal", jadi kasusnya sederhana.Dan di sini Anda memiliki versi yang sedikit dimodifikasi dari
TypeDescriptionProvider
:Dan itu dia!
Anda tidak perlu menjelaskan apa pun kepada pengembang formulir di masa mendatang berdasarkan BaseForm Anda dan mereka tidak perlu melakukan trik apa pun untuk merancang formulir mereka! Saya pikir ini adalah solusi paling bersih (kecuali untuk kontrol reposisi).
Satu tip lagi:
Jika karena alasan tertentu perancang masih menolak bekerja untuk Anda, Anda selalu dapat melakukan trik sederhana untuk mengubah
public class Form1 : BaseForm
kepublic class Form1 : BaseFormMiddle1
(atauBaseFormMiddle2
) di file kode, mengeditnya di perancang formulir VS dan kemudian mengubahnya kembali. Saya lebih suka trik ini daripada kompilasi bersyarat karena kecil kemungkinannya untuk melupakan dan merilis versi yang salah .sumber
Saya punya tip untuk solusi Juan Carlos Diaz. Ini bekerja dengan baik untuk saya, tetapi ada beberapa masalah dengannya. Ketika saya memulai VS dan masuk desainer semuanya bekerja dengan baik. Tetapi setelah menjalankan solusi, kemudian berhenti dan keluar dan kemudian mencoba untuk masuk desainer pengecualian muncul lagi dan lagi sampai restart VS. Tetapi saya menemukan solusinya - yang harus dilakukan adalah menambahkan di bawah ini ke app.config Anda
sumber
Karena kelas abstrak
public abstract class BaseForm: Form
memberikan kesalahan dan menghindari penggunaan perancang, saya datang dengan menggunakan anggota virtual. Pada dasarnya, alih-alih mendeklarasikan metode abstrak, saya mendeklarasikan metode virtual dengan tubuh seminimal mungkin. Inilah yang telah saya lakukan:Karena
DataForm
seharusnya kelas abstrak dengan anggota abstrakdisplayFields
, saya "memalsukan" perilaku ini dengan anggota virtual untuk menghindari abstraksi. Perancang tidak mengeluh lagi dan semuanya berfungsi dengan baik untuk saya.Ini adalah solusi yang lebih mudah dibaca, tetapi karena ini tidak abstrak, saya harus memastikan bahwa semua kelas anak
DataForm
menerapkannyadisplayFields
. Jadi, berhati-hatilah saat menggunakan teknik ini.sumber
Desainer Formulir Windows sedang membuat contoh kelas dasar formulir / kontrol Anda dan menerapkan hasil parse
InitializeComponent
. Itulah mengapa Anda bisa mendesain formulir yang dibuat oleh wizard proyek bahkan tanpa membangun proyek. Karena perilaku ini, Anda juga tidak dapat mendesain kontrol yang diturunkan dari kelas abstrak.Anda dapat mengimplementasikan metode abstrak tersebut dan membuat pengecualian jika tidak berjalan di desainer. Pemrogram yang berasal dari kontrol harus menyediakan implementasi yang tidak memanggil implementasi kelas dasar Anda. Jika tidak, program akan macet.
sumber
Anda bisa saja mengkompilasi secara kondisional dalam
abstract
kata kunci tanpa menempatkan kelas terpisah:Ini berfungsi asalkan
BaseForm
tidak memiliki metode abstrak apa pun (abstract
kata kunci karena itu hanya mencegah instance runtime kelas).sumber