10

何度も何度も出てくる状況に苦しんでいますが、自分のやり方が間違っているのか、それとも別のやり方でできるのかわかりません.

例:

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

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

これらのクラスを使用すると、基本クラスの public メソッドがインターフェイスを形成し、必要な特定のタイプの datagridview をインスタンス化し、共通インターフェイスを介して操作できます。素晴らしい。

問題:

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

いくつかの解決策:

現時点では、オーバーライドしたい基本クラスのメソッドを「実装」しています。

    throw new NotSupportedException();

少なくとも、インターフェイスを形成するこれらのメソッドのいずれかをオーバーライドするのを忘れた場合。これは私にはかなり臭いようですが、私はそれがあまり好きではありません.

私が考えたもう 1 つの解決策は、継承を完全に廃止し、インターフェイス (IMyDataGrid など) を定義して、それを各 datagridview クラス (一種の戦略パターン) に実装することでした。ただし、ここでの問題は、継承によって多くの異なるフォームを作成し、それらにデータグリッドビューをドロップする必要があることを意味するコードの再利用の利点を失うことです。同じコードをそれぞれに効果的にコピーして貼り付けます。悪い。

これを達成しようとするより良い方法はありますか?

4

3 に答える 3

4

要件に応じて、これを行うには多くの方法があります。

  • カスタム ロジックを実行するインターフェイスを実装するユーザー コントロールにフォームコンテンツを配置します。
  • DataGridViewカスタム ロジックを実行するインターフェイスを実装する派生クラス
  • 前述のように、クラスを使用する代わりに、メソッドで具象クラスを使用しvirtualますabstract
  • ...

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

于 2010-03-04T16:50:10.530 に答える
1

このメソッドをチェックして、必要な 2 つの属性を作成する方法を確認してください。

次の属性と型記述子クラスが必要です (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() { }
}

これはうまくいくはずです。

于 2009-08-20T15:14:49.627 に答える
0

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

より良い解決策は見つかりませんでしたが、ないようです。実際、Windows フォーム デザイナは、クラスの設計を変更することを強制しています。

于 2010-03-04T14:51:47.170 に答える