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 menjadi Form1
). The TypeDescriptionProvider
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:
[TypeDescriptionProvider(typeof(AbstractControlDescriptionProvider<BaseForm, BaseFormMiddle2>))] // BaseFormMiddle2 explained below
public abstract class BaseForm : Form
{
public BaseForm()
{
InitializeComponent();
}
public abstract void SomeAbstractMethod();
}
public class Form1 : BaseForm // Form1 is the form to be designed. As you see it's clean and you do NOTHING special here (only the the normal abstract method(s) implementation!). The developer of such form(s) doesn't have to know anything about the abstract base form problem. He just writes his form as usual.
{
public Form1()
{
InitializeComponent();
}
public override void SomeAbstractMethod()
{
// implementation of BaseForm's abstract method
}
}
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 ke TypeDescriptionProvider
dari BaseForm
. Tidak ada kompilasi bersyarat.
Saya mengalami dua masalah lagi:
- Masalah 1: Setelah mengubah Form1 di desainer (atau beberapa kode) itu memberikan kesalahan lagi (ketika mencoba membukanya lagi di desainer).
- Masalah 2: Kontrol BaseForm ditempatkan secara tidak benar ketika ukuran Form1 diubah di desainer dan formulir ditutup dan dibuka kembali di desainer formulir.
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.
class BaseFormMiddle1 : BaseForm
{
protected BaseFormMiddle1()
{
}
public override void SomeAbstractMethod()
{
throw new NotImplementedException(); // this method will never be called in design mode anyway
}
}
class BaseFormMiddle2 : BaseFormMiddle1 // empty class, just to make the VS designer working
{
}
Dan di sini Anda memiliki versi yang sedikit dimodifikasi dari TypeDescriptionProvider
:
public class AbstractControlDescriptionProvider<TAbstract, TBase> : TypeDescriptionProvider
{
public AbstractControlDescriptionProvider()
: base(TypeDescriptor.GetProvider(typeof(TAbstract)))
{
}
public override Type GetReflectionType(Type objectType, object instance)
{
if (objectType.FullName == typeof(TAbstract).FullName) // corrected condition here (original condition was incorrectly giving false in my case sometimes)
return typeof(TBase);
return base.GetReflectionType(objectType, instance);
}
public override object CreateInstance(IServiceProvider provider, Type objectType, Type[] argTypes, object[] args)
{
if (objectType.FullName == typeof(TAbstract).FullName) // corrected condition here (original condition was incorrectly giving false in my case sometimes)
objectType = typeof(TBase);
return base.CreateInstance(provider, objectType, argTypes, args);
}
}
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
ke public class Form1 : BaseFormMiddle1
(atau BaseFormMiddle2
) 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 .