StrataFrame Forum

Form inheritance - how is it achieved?

http://forum.strataframe.net/Topic7929.aspx

By Peter Jones - 4/5/2007

Hi,

I was hoping I could create a "base" SF Maintenance form that will contain standard code and components, e.g. DefaultLookAndFeel, then inherit this form whenever I create a new form. I have my base form called frmBase_01 and, the code in my test form that is trying use the base form is:

Public Class frmBase_02
   Inherits TMS_Test_01.frmBase_01
End Class

 This generate the error:
"Error 1 Base class 'frmBase_01' specified for class 'frmBase_02' cannot be different from the base class 'MicroFour.StrataFrame.UI.Windows.Forms.StandardForm' of one of its other partial types. C:\Documents and Settings\pmj\My Documents\Visual Studio 2005\Projects\TMS_Test_01\TMS_Test_01\frmBase_02.vb"

Try as I may I just can't stumble my way past this error - can you please point me in the right direction. The recent work I've done with creating a "base" BO class works great but I notice that, for forms, the inheritence is in the partial class - I guess this is a fundemental difference that stops my base BO approach working when trying to achieve the same outcome for a form.

Cheers, Peter

By Ivan George Borges - 4/6/2007

Hi Peter.

I'm sure you will be properly directed here, but I have the feeling that the way to go would be to make a template of your "frmBase_01". So you could create your own Standard and MaintenanceForm templates, and just Add them into your project, instead of the SF ones.

Abraços.

By Trent L. Taylor - 4/6/2007

Ivan is exactly correct here.  The StrataFrame Maintenance for is nothing more than an SF StandardForm with a Gradient Form Header and MaintenanceToolStrip already dropped on it.  This is all setup in a template file.

The easiest way to achieve what you are trying to do is to create your own template that already has the controls and code "pre-built" which gives you a big leg up when developing your specific application.

All item template files are actually stored in a ZIP in the following location:

C:\Program Files\Microsoft Visual Studio 8\Common7\IDE\ItemTemplates\VisualBasic

or

C:\Program Files\Microsoft Visual Studio 8\Common7\IDE\ItemTemplates\CSharp

You can extract these template files and open up the internal files to see what is done.  You can then create a form or other control to your liking and create your own ZIP file with the contained contents.

Once you have the ZIP file created and placed in the same folder as mentioned above (be sure to create a unique template name and ZIP file name) then you need to install it.  To do this close down Visual Studio, go to the Visual Studio command prompt and type:

devenv.exe /setup

Once complete your template will then be installed when you go back into Visual Studio.

By Greg McGuffey - 4/6/2007

Peter,



I've done this. The trick is to make you base form inherit from the SF standard form (Microfour.StrataFrame.UI.Windows.Forms.StandardForm). Then have your derived forms inherit from this base form. As you indicated, the inheritance is in the designer.



E.g.

base form with common code, in the desinger file:



Partial Class myBaseForm

Inherits MicroFour.StrataFrame.UI.Windows.Forms.StandardForm

...

End Class







Then in any of your main forms that will use this, again in the designer file:



Partial Class mySpecificForm

Inherits myBaseForm

...

End Class




Once you have this working, then I think Ivan and Trent are suggesting that you make it a VS template, to ease the use of the base class. I haven't gotten around to doing that yet with mine...but I'm going to! BigGrin



Hope this helped.


By Trent L. Taylor - 4/6/2007

Greg is correct as to which for should be inherited.  And there is obviously a need to do this in many cases, which this may be one...only you can answer that Smile.  But templates give you a great way to extend your development environment by adding code within the created form that may have preset functionality but can be overwritten on a per form basis without consequence.

An example of this is the custom login form.  If you create a custom login form you will really see the template at work as this form has quite a bit code already in it.

By Peter Jones - 4/6/2007


Hi Guys,

Yes, I did find references to creating a new template in the SF Forums but it did look a bit 'hard core' so I was attempting to take a light weight approach (like it would seem Greg has already done) however, for me, this didn't work out. So I followed you recommendation and returned to the 'new template' approach. Trent's instructions made it seem quite easy but I'm afraid it wasn't for a newbie.

Extracting the existing template files into a new directory doesn't actually create a project - just four files. While the code is there what isn't is a UI for dropping additional controls onto a form. Do I have to hand code all that side of things in the designer file or is there an easier way? I tried creating a new project and copy/pasted the code into a form but that generated the error:

--------------------
The designer could not be shown for this file because none of the classes within it can be designed. Hide at System.ComponentModel.Design.Serialization.CodeDomDesignerLoader.EnsureDocument(IDesignerSerializationManager manager) at System.ComponentModel.Design.Serialization.CodeDomDesignerLoader.PerformLoad(IDesignerSerializationManager manager)
at Microsoft.VisualStudio.Design.Serialization.CodeDom.VSCodeDomDesignerLoader.PerformLoad(IDesignerSerializationManager serializationManager)
at System.ComponentModel.Design.Serialization.BasicDesignerLoader.BeginLoad(IDesignerLoaderHost host)
-------------------

So, I'm just unclear about what stage I'm at. Do I just have to slog it out and change all the designer code by hand? My concern here is the new controls that I want to add into my new template form?


Greg, thanks for the suggestion. Actually I had already tried that approach but it gave me this error: "withEvents variable 'GradientFormHeader1' conflicts with withEvents variable 'GradientFormHeader1' in the base class 'frmBase_01' and should be declared 'Shadows'." Both my forms where created from the SF DevEx Maintenance  Form. Given that I had that error and not being sure about the ongoing implications of tracking the cause and fixing it I didn't want to pursue it.

Cheers and happy Easter to all, Peter

By Greg McGuffey - 4/6/2007

Ah, so I completely missed how templates work. I'll look into this some more (for myself). In my case, inheritance works best because I have some code that then only needs to be maintained in one place, but I can see that templates could work better in some cases.
By Peter Jones - 4/6/2007

Hi Guys,

Ah, maybe the penny just dropped for me. Is what I should be doing is creating the form that I want then simply copying the designer code from that form into my new template code? If this is the case I can see I need to use the variable $safeitemname$ in a few spots and change the vstemplate file to my new name but what about the resx file - do I need to worry about changing anything there?

Greg, your comment about inheritence is very interesting - could it be that inheritence is simply the best approach anyway. Now that I think about does creating a new template just give a head start on things but doesn't help with future maintenance, i.e if I use MyTemplate01 as the base for my forms and, in six months time, find that I missed a facility that I need in all forms then I have to go back and recreate all my forms using the an updated version of MyTemplate01.

Alternatively, if all forms inherited from MyForm01 then I simply change MyForm01 and recompile - is this right?

Cheers, Peter

By Ivan George Borges - 4/7/2007

Hi Peter.

Ah, maybe the penny just dropped for me. Is what I should be doing is creating the form that I want then simply copying the designer code from that form into my new template code? If this is the case I can see I need to use the variable $safeitemname$ in a few spots and change the vstemplate file to my new name but what about the resx file - do I need to worry about changing anything there?

That is it, the $safeitemname$ is already going to be in the template you unzipped. As for the "vstemplate" file, I think you might have to add a reference to your project, and I had to create a Strong Name Key to my "_base" project to reference there, think that the guys will tell you more about this. The resx file will need to be changed if you inserted anything in your form as an icon, or something like that, then I expect that your resx file template will need to have that too.

I use MyTemplate01 as the base for my forms and, in six months time, find that I missed a facility that I need in all forms then I have to go back and recreate all my forms using the an updated version of MyTemplate01.

How have you created your form template? I, first of all, subclassed the SF StandardForm :

Partial Public Class $safeitemname$

Inherits MicroFour.StrataFrame.UI.Windows.Forms.StandardForm

So, this is what my PFNStandardForm starts with.

Then, my maintenance form template will inherit from this PFNStandardForm, which will be PFNMaintenanceForm:

Partial Public Class $safeitemname$

Inherits ProFilmeNET_Base.UI.Windows.Forms.PFNStandardForm

This way, it is possible to add code to the PFNStandardForm in the future, and have all my maintenance forms already created inherit the changes. I hope... Hehe

Have a great Easter.

By Trent L. Taylor - 4/7/2007

Hi Peter,

It looks like the light came on in your last post w00t.  There is not much to add to Ivan's post...he is exactly right.  Let us know if you have any troubles. 

By Peter Jones - 4/7/2007

Hi Guys,

Thanks for the help - I'm currently working my way through Ivan's feedback. I've extracted the existing template and copy/pasted info from my new form then zipped up the files into a new, uniquely named, zip file and copies it back into: C:\Program Files\Microsoft Visual Studio 8\Common7\IDE\ItemTemplates\VisualBasic.

I didn't know what was meant by Trent's instruction to go the Visual Studio command prompt but Google to the rescue and I followed the Start>Programs>Visual Studio 2005>Visual Studio Tools and found the command prompt in there. I click this and simply ended up in command window in C:\program files\Microsoft Visual Studio 8\VC. Given that my code is VB I changed the directory to: ..\VB and entered devenv.exe /setup. This seemed to run ok but when I started VS again the only templates I have are: Inherited Form and Inherited User Control.

Contary to all instructions I paniced and went back into the ..\VB directory and entered the devenv command again. No errors but still no templates. I then checked the event log which told me the command I needed was devenv/installvstemplates. However doing this in both the VC and VB directories had no effect.

Any clues on how I recover from this self inflicted wound?


Ivan, specifically on what you have done - its seems to be great approach but have you ever tried changing ProFilmeNET_Base.UI.Windows.Forms.PFNStandardForm and seen the changes perculate through on a rebuild of your app?


Cheers, Peter

By Ivan George Borges - 4/9/2007

Any clues on how I recover from this self inflicted wound?

Hi Peter, have you seen Pertti's post? http://forum.strataframe.net/Topic7973-10-1.aspx


Ivan, specifically on what you have done - its seems to be great approach but have you ever tried changing ProFilmeNET_Base.UI.Windows.Forms.PFNStandardForm and seen the changes perculate through on a rebuild of your app?

Yes, I have. So far, so good. But I'm not talking about visual inheritance, which seems to be a problem in VS.

By StrataFrame Team - 4/9/2007

A template is nice, Peter, but to answer the question in your first post, if you want to create a form with some basic code and then inherit that form by other forms, you can do exactly like you wanted within the first post.  Your only snag was that in each of the partial classes (that includes the .designer.vb file which was probably missed), you have to add the same inherits line.  Or, you can leave the inherits line off and only add it to one of the files (which is what .NET does by default by adding the inherits line to only the .designer.vb file).  The main reason you missed it was probably because the way silly VB hides most of the files within your project by default (as if MS thinks a VB programmer would be scared by seeing so many files in his solution explorer or something).  So, you have to go turn on the "Show All Files" button at the top of the Solution Explorer in order to see the .designer.vb file where the other Inherits line is.

So, if anyone answered this question in the tons of posts on this thread, thanks, but I was just skimming the thread and it didn't looked like all of the discussion was around templates.  Templates are great, and we have several for our projects, but all of our forms also inherit from a base form that is specific to the application... so you really need both.

By StrataFrame Team - 4/9/2007

Also, if you're making a custom template, then it's a lot easier to put the code in your "My Templates" folder than to put it in with all of the installed templates.  Do this:

Put the .zip file for the template in {My Documents}\Visual Studio 2005\Templates\ItemTemplates\Visual Basic.  This folder is much more user friendly than the other one for several reasons:

1)  Your template shows up under it's own grouping called "My Templates" at the bottom of the Add New Item dialog, not mixed in with all of the others.

2)  You don't have to close Visual Studio, call devenv.exe /setup and then reopen visual studio... just re-open the Add New Item dialog and the template will be re-read.

When we do a custom template for use with one of our commercial products, we don't generally put it in the folder with all of the installed templates for those reasons.  It's a whole lot easier to tweak your template if you don't constantly have to close VS to run devenv.exe /setup just to reinstall your template Smile

By StrataFrame Team - 4/9/2007

One last thing... there's an Export Template Wizard that can be reached from the File menu... it will get you 90-100% of the way there on creating a custom template.  Just get the form the way you want it then run through the wizard and it will create the .zip file and dump it into your "My Templates" folder.  It's a lot faster than copying an existing template and modifying it... unless you've done it lots of times, even then the wizard is probably still faster Wink

If you can't reach the wizard from the file menu, then you'll have to add the command to your menu by right-clicking somewhere on the toolbars within VS and choose Customize... at the bottom.  The "Export Template..." command is under the File category.  Just drag it out onto the toolbar or menu where you want it.

By Greg McGuffey - 4/9/2007

Greg, your comment about inheritence is very interesting - could it be that inheritenceis simply the best approach anyway. Now that I think aboutdoes creating a new template just give a head start on things but doesn't help with future maintenance, i.e if I use MyTemplate01 as the base for my forms and, in six months time, find that I missed a facility that I need in all forms then I have to go back and recreate all my forms using the an updated version of MyTemplate01.



Alternatively, if all forms inherited from MyForm01 then I simply change MyForm01 and recompile - is this right?




Peter, I'm thinking that using both is the best, as Ben said. I didn't get the template thing until reading this post though. BigGrin



Let me give you a couple of examples of some of the things done in my base form to demonstrate the usefulness of inheritance:



- It can be configured to set the title of the form based on the value of a field in a BO. Currently I'm setting the BO and the field name as properties in the base form, but it recently occurred to me that since my base form inherits from the SF standard form, I could have just used the BO collection...duh. Then I'd only need to set the field name. The base form has code to react to the navigated event and handles setting the title of the form. I.e. if it is an employee form, the title will be '[employee name] - Employee Form' were [employee name] is replaced by the name of the employee.

- I've included a SF Gradient header and a .NET tablelayout control just under it to show the client and project context of the form (most of my forms are within the context of client/project). The base form has a property so the project ID can be set. The base form handles the Load event of the form and sets the header up, looking up the client and project name using the project ID.



In both cases, if I find a bug or want to change the behavior I have one place to fix it. If I find myself copy/pasting the same code between forms, I start thinking about how to use inheritance to reuse the copy/pasted code. As an example, when I first coded the loading of the project/client name, I was looking it up always. Then I realized that in most cases I could cache this info, so I just changed the code to use a cache and a property to force a lookup. About 80% of the forms in my app used this base form and they all got fixed instantly. BigGrin I really like using inheritance because it allows very iterative programming. As I figure out that I have repetitive code in a form, I refactor, pulling out the repetitive code and put it my base form. I'm actually about to refactor my base form into two base forms, one that has very common code (like the title setting bit using a field form a BO) and my project base form (which would have the custom header for projects). Thus I'd have a specific project form inherit from the project base form which inherits from the general base form which inherits from the SF standard form which inherits from the .net form! This can get a bit confusing (because the features implemented in a form are spread all over the place..see note at end), but believe me, the first time you find a bug or want to change/add a feature that is in the general base form and see the change reflected instantly in ALL forms inheriting from it...oh baby w00t



However, to use this base form, I have to manually open the designer file and change the inheritance. This is where the template would be really nice. When I get a moment, I'm going to give it a try!



NOTE:

I've found that using xml comments and keeping them updated is very helpful as those comments get pushed into the object browser. This allows me to more quickly remember how I've done things. I can see the inheritance, which property/methods are in which of the inheritated forms etc.


By Peter Jones - 4/9/2007

Gentlemen,

Thanks for the great feedback guys - this is really got me rolling,

Ivan thanks for the link - I hadn't seen it however, guess what, this morning all my templates are back. I have no idea how that happened. I 'nearly' certain that I tried a VS restart when trying to fix the problem before but maybe I didn't.

I also followed Ben's advice re the location of the template file and that's much better.

About to start trying to bring this all together. If I find any interesting info that will be useful, as part of this thread, I add it in.

Cheers, Peter

By Ivan George Borges - 4/10/2007

Hey Peter.

Glad to hear that.

Wink