TypeDescriptionProvider
Juan Carlos Diaz'ın çalışmadığını söyleyen ve şartlı derlemeyi de sevmeyenler için bazı ipuçlarım var :
Her şeyden önce, kodunuzdaki değişikliklerin form tasarımcısında çalışması için Visual Studio'yu yeniden başlatmanız gerekebilir (mecburdum, basit yeniden oluşturma işe yaramadı - veya her seferinde değil).
Soyut temel Form durumu için bu problemin çözümünü sunacağım. Diyelim ki bir BaseForm
sınıfınız var ve ona dayalı herhangi bir formun tasarlanabilir olmasını istiyorsunuz (bu olacak Form1
). TypeDescriptionProvider
Juan Carlos Diaz tarafından sunulan da benim için çalışmadı. İşte onu MiddleClass çözümüne (smelch ile) katılarak, ancak koşullu derleme olmadan#if DEBUG
ve bazı düzeltmeler yaparak nasıl çalıştırdım:
[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
}
}
BaseForm sınıfındaki özniteliğe dikkat edin. O zaman sadece TypeDescriptionProvider
ve iki orta sınıfı ilan etmeniz gerekir , ancak endişelenmeyin, bunlar Form1'in geliştiricisi için görünmez ve alakasızdır . İlki soyut üyeleri uygular (ve temel sınıfı soyut olmayan yapar). İkincisi boş - sadece VS form tasarımcısının çalışması için gereklidir. Sonra ikinci orta sınıfı TypeDescriptionProvider
of sınıfına atarsınız BaseForm
. Koşullu derleme yok.
İki sorun daha yaşıyordum:
- Sorun 1: Tasarımcıda (veya bazı kodlarda) Form1'i değiştirdikten sonra, hatayı yeniden veriyordu (tasarımcıda yeniden açmaya çalışırken).
- Sorun 2: BaseForm denetimleri, Form1'in boyutu tasarımcıda değiştirildiğinde ve form tasarımcısında kapatılıp yeniden açıldığında yanlış yerleştirildi.
İlk sorun (buna sahip olmayabilirsiniz çünkü bu, projemde beni başka birkaç yerde rahatsız eden bir şeydir ve genellikle "X türünü X türüne dönüştüremiyorum" istisnası üretir). Ben bunu çözmüş TypeDescriptionProvider
tarafından tip isimleri karşılaştıran yerine türlerini karşılaştırma (FullName) (aşağıya bakınız).
İkinci sorun. Temel form kontrollerinin neden Form1 sınıfında tasarlanamadığını ve konumlarının yeniden boyutlandırıldıktan sonra kaybolduğunu gerçekten bilmiyorum, ancak bunun üzerinde çalıştım (iyi bir çözüm değil - daha iyisini biliyorsanız, lütfen yazın). BaseForm'un Load olayından eşzamansız olarak çağrılan bir yöntemde BaseForm düğmelerini (sağ alt köşede olması gerekir) manuel olarak doğru konumlarına hareket ettiriyorum: BeginInvoke(new Action(CorrectLayout));
Temel sınıfım yalnızca "Tamam" ve "İptal" düğmelerine sahip, bu nedenle durum basit.
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
{
}
Ve burada şunun biraz değiştirilmiş versiyonuna sahipsiniz 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);
}
}
Ve bu kadar!
Gelecekteki form geliştiricilerine BaseForm'unuzu temel alan herhangi bir şey açıklamanız gerekmez ve formlarını tasarlamak için hiçbir numara yapmaları gerekmez! Bence olabilecek en temiz çözüm (kontrollerin yeniden konumlandırılması hariç).
Bir ipucu daha:
Nedense tasarımcı hala senin için işe reddederse, her zaman değişen basit hile yapabilirsiniz public class Form1 : BaseForm
için public class Form1 : BaseFormMiddle1
(veya BaseFormMiddle2
kod dosyasında) VS form tasarımcısı düzenleyerek ve sonra geri yeniden değiştirmeyi. Bu numarayı koşullu derlemeye tercih ediyorum çünkü yanlış sürümü unutup yayınlama olasılığı daha düşük .