2009-08-20 101 views
9

我一直在一次又一次地出現,但我不確定我做事的方式是錯誤的,還是我可以以不同的方式做事。使用Windows窗體作爲抽象類 - 使用哪種模式?

一個例子:

我有了一些私有方法一個DataGridView執行DataGrid的驗證和解釋上的DataGridView鼠標右鍵單擊Windows窗體等,這windows窗體本質上是一種「抽象的」類並且從不直接實例化。然後,我繼承這個基類,並以各種方式(模板模式)對其進行自定義,例如,定義datagridview的列和特定於這些列的特定格式化方法等。

當我使用這些類時,基類public方法形成我的接口,並且可以實例化我想要的特定類型的datagridview並對其進行操作通過通用接口。可愛。

問題:

的主要問題是,你不能真正宣佈Windows窗體類的抽象,而不會導致Visual Studio設計扔不穩定,因爲它無法實例化這些抽象類。

一些解決方案:

在我「落實」在基類中的方法,我想與被覆蓋的那一刻:

throw new NotSupportedException(); 

所以至少如果我忘了重寫的一個這些方法構成了我的界面。這對我來說似乎很臭,但我並不喜歡它。

我玩弄的另一個解決方案是完全消除繼承,並定義一個接口(例如IMyDataGrid)並在每個datagridview類(策略模式)中實現該接口。但這裏的問題是,你失去了代碼重用的好處,繼承給你的意思是你必須創建許多不同的表單,在它們上面放置一個datagridview - 有效地將相同的代碼複製並粘貼到每個表單中。壞。

有沒有更好的方法來實現這個目標?

+0

爲什麼不直接從GridView繼承並創建一個在Windows窗體上使用的控件? – Macros 2009-08-20 15:06:55

回答

4

根據您的要求,有很多方法可以做到這一點。

  • 把形式內容成從DataGridView實現接口做定製邏輯
  • 如前所述實現一個接口做定製邏輯
  • 派生的類的用戶控制,用一個具體類virtual方法而不是使用abstract
  • ...

您必須選擇最適合您需求的選項。如果不知道問題所在的領域和具體情況,我認爲我們不能給你一個100%肯定的答案。

+0

這些建議是好的! – Calanus 2010-05-15 06:38:40

1

檢查出this method知道如何創建所需的兩個屬性。

您需要以下屬性和類型說明符類(從UrbanPotato採取代碼)

// Source : taken from http://www.urbanpotato.net/default.aspx/document/2001 Seem to be down 
// Allow the designer to load abstract forms 
namespace YourNamespace 
{ 

    // Place this attribute on any abstract class where you want to declare 
    // a concrete version of that class at design time. 
    [AttributeUsage(AttributeTargets.Class)] 
    public class ConcreteClassAttribute : Attribute 
    { 
     Type _concreteType; 
     public ConcreteClassAttribute(Type concreteType) 
     { 
      _concreteType = concreteType; 
     } 

     public Type ConcreteType { get { return _concreteType; } } 
    } 

    // Here is our type description provider. This is the same provider 
    // as ConcreteClassProvider except that it uses the ConcreteClassAttribute 
    // to find the concrete class. 
    public class GeneralConcreteClassProvider : TypeDescriptionProvider 
    { 
     Type _abstractType; 
     Type _concreteType; 

     public GeneralConcreteClassProvider() : base(TypeDescriptor.GetProvider(typeof(Form))) { } 

     // This method locates the abstract and concrete 
     // types we should be returning. 
     private void EnsureTypes(Type objectType) 
     { 
      if (_abstractType == null) 
      { 
       Type searchType = objectType; 
       while (_abstractType == null && searchType != null && searchType != typeof(Object)) 
       { 

        foreach (ConcreteClassAttribute cca in searchType.GetCustomAttributes(typeof(ConcreteClassAttribute), false)) 
        { 
         _abstractType = searchType; 
         _concreteType = cca.ConcreteType; 
         break; 
        } 
        searchType = searchType.BaseType; 
       } 

       if (_abstractType == null) 
       { 
        // If this happens, it means that someone added 
        // this provider to a class but did not add 
        // a ConcreteTypeAttribute 
        throw new InvalidOperationException(string.Format("No ConcreteClassAttribute was found on {0} or any of its subtypes.", objectType)); 
       } 
      } 
     } 

     // Tell anyone who reflects on us that the concrete form is the 
     // form to reflect against, not the abstract form. This way, the 
     // designer does not see an abstract class. 
     public override Type GetReflectionType(Type objectType, object instance) 
     { 
      EnsureTypes(objectType); 
      if (objectType == _abstractType) 
      { 
       return _concreteType; 
      } 
      return base.GetReflectionType(objectType, instance); 
     } 


     // If the designer tries to create an instance of AbstractForm, we override 
     // it here to create a concerete form instead. 
     public override object CreateInstance(IServiceProvider provider, Type objectType, Type[] argTypes, object[] args) 
     { 
      EnsureTypes(objectType); 
      if (objectType == _abstractType) 
      { 
       objectType = _concreteType; 
      } 

      return base.CreateInstance(provider, objectType, argTypes, args); 
     } 
    } 
} 

將它們分配給您的抽象形式是這樣的:

[TypeDescriptionProvider(typeof(GeneralConcreteClassProvider))] 
[ConcreteClass(typeof(MyAbstractConcreteForm))] 
public abstract partial class MyAbstractForm : Form 
{ 
} 

創建一個新的類,它繼承你的抽象形式。這個類將由Visual Studio實例化

public class MyAbstractConcreteForm: MyAbstractForm 
{ 
    public MyAbstractConcreteForm() : base() { } 
} 

這應該有效。

+1

@ Pierre-Alain Vigeant:您提到的網頁是順便提及的。 – Marc 2010-03-04 14:52:13

+0

我懷疑網站的工作方式發生了變化。指向那裏的大多數鏈接不再解決。請參閱有關此問題的Microsoft Connect問題http://connect.microsoft.com/VisualStudio/feedback/details/322712/forms-designer-cannot-show-form-that-inherits-from-an-abstract-form,並指出到我寫的鏈接。我會盡力找到另一個參考。 – 2010-03-04 16:30:59

+1

上面的方法可能會好,但sheesh做了很多工作! – Calanus 2010-05-15 06:37:32