2009-08-20 97 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