views:

55

answers:

6

I don't know what this is called so I've struggled to find an answer from google but I have a vague memory of it from t'old days.

I've sub-classed (* see below) about 8 framework controls, overriden some properties and added some functionality into each one. The changes I have made are identical in every case. If I make a change, I have to go through each class and apply the same change there. I was hoping there may be a keyword such as <IncludeSourcefile "common.vb> that I can put into each class.

Any chance?

(* note) I use the term sub-classed but I don't know if that's the correct terminology. I've also seen it used for call-backs. Is sub-classed the correct term to use?

A: 

Compile your common classes into their own DLL.

Then set the reference for your DLL in Visual Studio by right-clicking on the References folder in the Solution Explorer.

Finally, add Using statements to your project's classes for the namespace(s) in your new DLL.

Robert Harvey
See my comment to JohnIdol above...erm below, or whereever it ends up; the fricking post moved!
Jules
+1  A: 

I seriously doubt that's going to work out for you. You can't use an include file to jam the changes into the derived controls. You'd normally make the changes in a common base class, one derived from Control for example, then derive individual controls from that base class. But that's not going to work if you customized 8 separate control classes. Copy-and-paste is your lot.

Hans Passant
That's a shame. I can't think of many reasons you'd need such a feature, but with this particular situation, it's the only way to avoid cut-and-paste.
Jules
A: 

You can create a class library project (which output will be a dll) from visual studio:

New Project --> Class Library

You can put all your code there then you can simply add a reference to the class library to the project you want to use it from (right click references on solution explorer):

References --> Add Reference --> Projects --> MyClassLibrary

To be able to find MyClassLibrary in the projects tab both projects need to be in the same solution - otherwise ou can just go 'browse' and point to the dll itself.

Then in the .vb file you need to use your classes you can do an import MyClassLibrary:

// assuming the namespace is MyClassLibrary
imports MyClassLibrary

At this point you can just use your subclasses and controls. If you go MyClassLibrary. intellisense will show you all your classes.

JohnIdol
Hi, I think you misunderstood my situation. I'm deriving from existing controls such a button, checkbox, label etc. Multiple inheritance is not possible, and even if it was (i've never used it), I still don't think it would apply to this case.
Jules
I am not talking about multiple inheritance - just showing you how to put your classes in a dll and reference that from the project
JohnIdol
+1  A: 

This might be a crazy idea but...

  1. Create a common.vb file with the code you need.
  2. Create partial classes files for each of your controls where you will add the sample code.
  3. Create a batch file that copy the data from your common.vb into your partial classes
  4. Create a pre-building step that executes that batch file.

If you need the code copied to the partial classes before compilation, you can always run the batch file.

And that is of course assuming that VB.NET has the concept of partial classes. And NO, I didn't tried that at home... ;-D

Wagner Silveira
Hi, yes vb.net does have partial classes. I've never created nor included a batch file in the pre-build before. I'll have a look at that. Off the top of my head though, I presume the batch file would need a bit of intelligence - such as knowing what to call each partial file, or, if not that, knowing to paste the code after the class begin statement?
Jules
I was calling a batch file, but if you need intelligence, you might need to create an application to do just that... I told you that might be a crazy idea... ;-D
Wagner Silveira
+1  A: 

I'd support nobugz's answer. Even if there was an #Include statement, I don't think that would be a good idea. Any change in the include file might easily break any of your 8 subclassed user controls.

BUT: What just might work, if all of the common changes can be integrated into the subclassed user controls via event handlers, or if the changes are of the type where you set common properties of your user controls to particular values, is a class that applies the code changes to any user control passed to it:

Class CommonChanges

    Private Readonly WithEvents DerivedUserControl As Windows.Forms.Control

    Public Sub New(ByVal derivedUserControl As Windows.Forms.Control)
        Me.DerivedUserControl = derivedUserControl
    End Sub

    Private Sub DerivedUserControl_OnClick(sender As Object, e As EventArgs) _
                Handles DerivedUserControl.Click
        ' ... '
    End Sub

    ...  ' (more event handlers with common code go here) '

End Class

Then, you define your 8 customized user controls like:

Class MyDerivedUserControl
    Extends Button  ' (or whatever control it extends) '

    Private ReadOnly Changes As CommonChanges

    Public Sub New
        Changes = New CommonChanges(Me)
        ' ^ 'CommonChanges' will subscribe to this class's events and possibly
        '   apply other changes to the control object 'Me'.
        ...
    End Sub
End Class

That object Changes of type CommonChanges will subscribe to events of your MyDerivedUserControl class and hook the handlers defined in CommonChanges to them.

Also, you can directly apply changes to the Control object passed to CommonChanges's constructor this way.

stakx
Hi that's an interesting idea but it won't work. 50% of the code is shadowing existing properties so that I can modify the attributes to hide them from the property grid and editor. Why don't you think an include statement would be a good idea? If I had control over the control class and removed a property or method, or changed a signature, I'd break all the dependants. It's the same thing. (eta it's the same thing at run time).
Jules
@Jules: If you want to hide properties from the property grid, maybe you could have a look at `TypeDescriptor` and `ICustomTypeDescriptor`. Implementing the latter interface should give you the possibility to control how, and which, properties are exposed. I haven't done this myself but it might be worth looking into. -- And yes, you're probably right that include files would work just as well. It's just that I've gotten into the habit of *not* using them, and I don't miss them. I remember from my C++ days that changing something in an include file could easily break several code files.
stakx
Hi, i've used ICustomTypeDescriptor in the past, but, in this case, it's nice to have the properties and methods hidden from intellisense as well. Thanks for the info anyway.
Jules
+1  A: 

I remember reading somewhere that Microsoft made a specific design decision (at least in C#) not to allow including external source code in this way.

It was felt that while including source files could be useful in C++, it could also introduce complexity and reduce readability.

In an OO language there are usually good alternatives, the most obvious being object composition and delegation.

Here's how I've handled this situation in the past:

class CommonCode
{
    public void HandlePaint(Control c, PaintEventArgs a)
    {
        // Do shared code
    }
    public void HandleResize(Control c)
    {
        // Do shared code
    }

}

class MyButton : Button
{
    private CommonCode m_common=null;

    public MyButton()
    {
        m_common=new CommnCode();        
    }
    protected override OnPaint(PaintEventArgs a)
    {
        m_common.HandlePaint(this,a);
    }

    protected override void OnResize(EventArgs e)
    {
        m_common.HandleResize(this);
    }

}

class MyTextbox :Textbox
{

    private CommonCode m_common=null;

    public MyTextbox()
    {
        m_common=new CommnCode();        
    }
    protected override OnPaint(PaintEventArgs a)
    {
        m_common.HandlePaint(this,a);
    }

    protected override void OnResize(EventArgs e)
    {
        m_common.HandleResize(this);
    }

}
Ash
That's similar to what I suggested; only your code example is much much clearer. +1 for that.
stakx