2009-08-20 11 views
9

私は何度も何度も何度もやって来る状況に苦しんでいますが、私がやっているやり方が間違っているのか、別のやり方でやり遂げることができるのかどうかはわかりません。Windowsフォームを抽象クラスとして使用する - どのパターンを使用するのですか?

アン例:

が、私はデータグリッドの検証を実行するためにいくつかのプライベートメソッドを持つのDataGridViewを持つWindowsフォームを持っているとのDataGridViewなどの上にマウスの右クリックを解釈するこのWindowsフォームは、本質的に「抽象」クラスです。直接インスタンス化されることはありません。

次に、この基本クラスから継承し、さまざまな方法(テンプレートパターン)でカスタマイズします。データグリッドビューの列とそれらの列に固有の特定の書式設定メソッドを定義します。

これらのクラスを使用すると、基本クラスのパブリックメソッドが自分のインターフェイスを形成し、必要なデータグリッドビューの特定の型をインスタンス化できます共通のインターフェースを介して。美しい。

問題:

主な問題は、あなたが実際にはこれらの抽象クラスをインスタンス化することはできませんとしてグラグラをスローするようにVisual Studioのデザイナーを発生させることなく、抽象としてWindowsフォームクラスを宣言することができないということです。

いくつかのソリューション:そう、少なくとも私は、のいずれかを上書きするのを忘れた場合

throw new NotSupportedException(); 

私は私が上書きされたい基底クラスでこれらのメソッドを「実装」しています瞬間私のインターフェースを形成するこれらのメソッド。これは私にとってはむしろ臭いようですが、私は本当にそれが好きではありません。

私がおもしろい別の解決策は、継承を完全に取り除き、インターフェース(例えばIMyDataGrid)を定義し、それを各datagridviewクラス(戦略パターンの一種)で実装することでした。しかし、ここでの問題は、コードの再利用の利点を失うということです。継承とは、さまざまなフォームを作成し、それらにデータグリッドビューをドロップし、同じコードを効果的にコピーして貼り付けるという意味です。悪い。

これを達成するためのよりよい方法がありますか?

+0

GridViewから直接継承し、Windowsフォームで使用するコントロールを作成するのはなぜですか? – Macros

答えて

4

要件に応じてさまざまな方法があります。

  • コンクリートを使用し、前述のように、カスタム・ロジック
  • を行うためのインタフェースを実装するDataGridViewからクラスを派生カスタムロジックを行うためのインタフェースを実装し、ユーザーコントロールにフォームコンテンツを入れて代わりにabstractクラス
  • を使用するvirtualメソッドを持つクラス...

あなたのニーズに最も適したオプションを選択する必要があります。あなたの質問が尋ねられているドメインと詳細を知らないと、私はあなたに100%答えを与えることはできないと思います。

+0

これらの提案は良いものです! – Calanus

1

this methodを調べて、必要な2つの属性を作成する方法を知ってください。

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

が継承する新しいクラスを作成します。あなたは次の属性および型記述子クラス(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); 
     } 
    } 
} 

は、このようなあなたの抽象フォームに割り当てる必要

あなたの抽象的なフォーム。このクラスはVisual Studioによってインスタンス化されます

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

これは動作するはずです。

+1

@ Pierre-Alain Vigeant:あなたが言及したウェブページは途中で消えています。 – Marc

+0

私はウェブサイトの仕組みの変化を疑う。そこを指すほとんどのリンクはもはや解決されません。この問題に関するMicrosoft Connectの質問を参照してください。http://connect.microsoft.com/VisualStudio/feedback/details/322712/forms-designer-cannot-show-form-that-inherits-from-an-abstract-form私が書いたリンクに。私は別の参考文献を見つけようとします。 –

+1

上記の方法はおそらく大丈夫でしょうが、何が大変な作業ですか? – Calanus

0

私は同じ問題があります。
このページは、回避策でもありますが、Inheriting a Form from an Abstract Class (and Making it Work in the Designer)に役立つ場合があります。

もっと良い解決策はありませんでしたが、そうは思われません。したがって、実際にはWindowsフォームデザイナーは、クラスデザインを変更する必要があります。

関連する問題