Use Form(Of T) on VS Designer - vb.net

I'm using vb.net (vs2010). I'm moving some winforms to a dll. I have a form that inherits from the one which has some subs and functions (like a test app).
My original form is: (.designer)
Partial Class Form1(Of T)
Inherits System.Windows.Forms.Form
....
End Class
Form itself contains code and a toolbar.
My test form is: (.designer)
Partial Class TestForm
Inherits Form1(Of Class1)
I get "Cannot create an instance of Form1`1[T] because Type.ContainsGenericParameters is true" when VS try to load the designer. App is usable. I can build and run the project without errors, but I need to add controls and some code to each new form.
I tried many ways:
Visual Studio 2008 Winform designer fails to load Form which inherits from generic class
How can I get Visual Studio 2008 Windows Forms designer to render a Form that implements an abstract base class?
http://www.codeproject.com/Questions/419770/Csharp-reflection-GetValue-from-a-field-in-generic
http://madprops.org/blog/Designing-Generic-Forms/
All examples are for C#, and I don't know if I'm missing something...
Is this a bad design ? I know this is a VS bug but still it seems everyone fixed it by these links.
EDIT:
I'm building a DLL. Form1 is on this DLL and TestForm is in a new project. Those links works if I'm in the same project (a.k.a. the dll).
Thanks!

Is this a bad design ? I know this is a VS bug
Bad design, not a VS bug. What you are trying to do is fundamentally incompatible with the way the Winforms designer works. It has strong WYSIWYG support, the designer creates an instance of the form's base class and allows code in that base class to run at design time. Which is why, for example, you can set the BackgroundImage property and it is immediately visible in the designer. The Form.OnPaintBackground() method paints it. The designer is not involved at all, it just sets the property.
To make that work, it must be able to create the base class object. It can't in your code, it doesn't know what kind of T to use. Not an issue when you design Form1, the T isn't needed yet since it derives from Form and creating an instance of Form is not a problem. Big issue when you design TestForm.
You'd probably argue that it should use Class1 as the T. It doesn't, the odds that it can use Reflection to discover the generic type argument from TestForm are exceedingly low. That requires the type to be compiled first. That's a chicken-and-egg problem at design time, the TestForm class gets compiled after you design it, not before or while you design.
It's not like you completely cannot use your approach. It builds and runs just fine. You just have to live without design time support for TestForm. That's usually a deal breaker, you have to re-consider your design.

Related

Issue with OpenFileDialog and threading

I just upgraded from VS 2005 to VS 2012. This is a new issue that I do not understand. I am using the default "Form1" class the VS automatically creates. I added a button to open a file open dialog and when I click the button I get this error:
Current thread must be set to single thread apartment (STA) mode before OLE calls can be >made. Ensure that your Main function has STAThreadAttribute marked on it. This exception >is only raised if a debugger is attached to the process.
I have added " to Public Class Form1:
<STAThread()> Public Class Form1
But I get this...
Attribute 'STAThreadAttribute' cannot be applied to 'Form1' because the attribute is not >valid on this declaration type.
I have searched but get some info telling me that I need to set the entry point (Form1 I believe) to be Single Thread Attribute but the above code does not work.
How?
The <STAThread()> attribute cannot be added to classes like your form. It only works when it is applied to the Main function, which is the entry point of your application.
But VB.NET hides this function from you because it is rare that one needs to mess with Main in a WinForms application. It is just needed to get the plumbing set up for your app, which the compiler can manage for you. This is controlled by the "Application Framework" checkbox in the project options. If this is checked, the compiler automatically generates the Main function and the required plumbing. You can disable this option, but it makes life quite a bit harder for the average WinForms developer because you'll have to write and maintain your own Main function.
The real question here is why this is a problem at all. The compiler-generated Main function for a WinForms application is always going to have the STAThread attribute applied to it. That is just how the WinForms framework is designed to run. If that is not happening, then there is something badly wrong with your project. I would recommend scrapping it and starting over letting Visual Studio create a new WinForms project from one of the built-in templates. Everything should Just Work™.
The other option, of course, is that you're trying to display the OpenFileDialog on a separate thread (other than your main UI thread). But from your description in the question (adding a button to the form to display the dialog), it doesn't sound like this is the case. Regardless, the solution is not to do that. For example, if you're using a BackgroundWorker to do work on a non-UI thread in order to keep the UI responsive, that's great, but you'll want to do all of the UI stuff like showing an OpenFileDialog on the main UI thread before invoking the BackgroundWorker. There is a way to set a particular thread's apartment state using the SetApartmentState function, but I really don't recommend showing an OpenFileDialog on a background thread.

VB.NET UserControl

I am trying to create a UserControl in VB.net, under VS2010. I have the code for the UserControl and I would like to add it to a form. My problem is that, according to every book and forum I have seen, after I build the UserControl, it should show up in the Toolbox. It doesn't. I even downloaded code from a book, the code executes perfectly, but their TrafficLight control doesn't go in the Toolbox (even though the book says it should - and that the only way to set its properties and to add it to the form is through the Control properties). I have tried to add the control to the form manually, by declaring it
Dim myObj As New SomeClass.SomeControl
and in the Designer.vb, identical with the buttons on the form:
Friend WithEvents myObj As SomeClass.SomeControl
With both, I get an error saying
'myObj' is already declared as 'Friend WithEvents myObj As SomeControl' in this class.
And either way, I get an error when I try to look at the design:
Could not find type 'SomeClass.SomeControl'. Please make sure that the assembly that contains this type is referenced. If this type is part of your development project, make sure the project has been successfully built using settings for your current platform or AnyCPU.
The control by itself builds and shows up in design view (not in the Toolbox though, even though it Imports System.ComponentModel and Inherits System.Windows.Forms.UserControl and... what else ? I tried to build it in a separate project, to see if I creating a separate dll will make a difference, though I really want it in the same project.
Please help ! (BTW I have reinstalled VS2010 and it did no good)
Thank you.
Look in Tools / Options / Windows Forms Designer and set "AutoToolboxPopulate" to True (but note that this can take a noticeable amount of time if you haver many (i.e. dozens) of user controls.

Non visual inheritance of WinForms with vb.net

I have two Forms, which have similar Functionality (i.e. an amount of similar Controls) but complete different Layout. So the normal inheritedForm (which VS2010 provides) wont work here.
I have tried following:
Public Class BaseForm
Inherits System.Windows.Forms.Form
Friend WithEvents Button1 As System.Windows.Forms.Button
End Class
And in Form1.Designer.vb:
Partial Class Form1
Inherits BaseForm
...
<all Designer generated Code>
...
' Friend WithEvents Button1 As System.Windows.Forms.Button <- remove this Line
End Class
If i compile/execute this, the test form works as expected; But now I am unable to design the form any longer.
If I switch to Design-Mode, it says:
The variable 'Button1' is either undeclared or was never assigned.
So it looks like, the Designer only tries to guess how the Form looks like by inspecting the top-most Class, without compiling the full inheritance-Tree...
Does anyone know a workaround for this?
Thx,
Daniel
I have a feeling you have some existing controls on the base form which you want to bring to the inherited form and then add more functionality of your own. Remember one thing, inheritance in VB.NET is by default set to shadowing, so you can redefine code in your inherited page for the same button to do a different function.
However, I think you forgot the Overridable keyword when declaring the form elements in the parent form. This will help the compiler know that the form can be overridden and allow you to define custom functionality.
Remember, all controls and pages in VB.NET are classes and whatever we learned during OOP classes in college apply here.

Creating a Partial Class for a Form

I would like to create a partial class for my form. I have a lot of events, and it gets messy, so I would like to break up sections into their own files.
The problem: When I create a partial class of my form, say:
Partial Public Class Form1
End Class
Visual Studio decides I need another form for this partial class.
Questions:
1. How do I create a partial class for a form?
2. If I cant do that, how can I break up all the events in my form into different files?
Yeah, it does. As soon as you drop a control on this phantom form, you'll get the design-time code (InitializeComponent) generated into that source code file. This is compatibility behavior for .NET 1.x, it didn't support the Partial keyword. Which will break the build, there are now two of them. It is somewhat avoidable with careful clicking, but you know it's going to happen sooner or later.
Other things go wrong too btw, the designer can no longer track an event handler when you move it from one file to another. And will readily let you add another, a much trickier source of bugs.
This just doesn't work very well, abandon hope of relying on it to solve your problem.
The generic diagnostic is that a convoluted user interface begets convoluted code. But that ship has sailed, no doubt. A more structural solution is pursuing the MVC model, separating the data from the view of the data. You'll still have a lot of event handlers but they won't do anything more than calling a method of a class that does the real work. Whose source code can of course live in another source code file. The typical hangup is that Windows Forms has no support whatsoever built in for this, you have to craft it by hand. Nothing similar to the MVVM model in WPF.
Something that can work well is isolating control + code into a separate UserControl. You have to do so carefully though, you don't want to have to add a bunch of properties and events that expose internal controls.
Sometimes I create partial classes for better readibility, especially when I have very large classes.
But when I click on the partial class, then the VS IDE will open the form editor showing me an empty form. If I do not care, than I could damage the main form (it seems to be a bug of VS 2008/2010)
A possibility could be using DesignerCategoryAttribute Class
Mark the partial class with the attribute "code".
<System.ComponentModel.DesignerCategory("code")>
Partial Class Form1
End Class
In this way when you click on the file, you open the class in the code editor.
Of course this will apply to all files, also to the main form file.
If you want to edit again your form in the form editor, you have to quote the attribute:
'<System.ComponentModel.DesignerCategory("code")>
Some more details here.
While it does not answer the original question, I found using regions made my code a little more manageable/readable.
#Region "RegionA"
#End Region
I orginally called this method a "hack", thus the comment below.
Not sure what you mean be "Visual Studio decides you need another form", however, are you sure the new Form1 partial class is declared in the corresponding original namespace?
All partial classes for a given .NET type must be declared in the same namespace of course (whatever files they're stored on).
I appreciate the answers given by Hans and I'm not disputing these at all. It is curious though that in Visual Studio 2010, when you create a form called say Main you get a Main.designer.vb which is a partial class. It says 'Partial Class Main' at the top. This class doesn't open a form when clicked. It also includes reference to Event Handlers. So I was wondering how do they get around this? Is there a way to create one of these 'special' partial classes that work as we would expect.
I noticed that when I created a Form Partial class, that the icon went from a class icon to a form icon. The icon associated with the Main.designer.vb file looks like a class icon with a arrow.
what worked for me (VS 2010) was naming Form1 class, already saved in Form1.vb with its own designer (Form1.Designer.vb) as:
Public Class Main 'saved in Form1.vb
VS updated the name in the designer as:
Partial Class Main 'saved in Form1.Designer.vb
then I created another "partial class" with the same name:
Partial Class Main 'saved in Main.vb
Whether I am editing Form1.vb or Main.vb VS shows me on the top navigation pan all the routines, functions, subs, even background workers and timers. For event handlers, to avoid the loophole mentioned earlier (you click on a control in the layout designer and a brand new event handler will be created in the original Form1.vb) I go:
Partial Public Class Main 'in Form1.vb file
Private Sub SomeControl_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles SomeControl.Click
Call SomeControlClick(sender, e)
End Sub
End Class
Partial Public Class Main 'then in Main.vb file
Private Sub SomeControlClick(ByVal sender As Object, ByVal e As System.EventArgs)
'blah blah
End Sub
End Class

Creating your own component in vb.net 2008

How do you create your own custom component for vb.net 2008? I want it to simply output to a .dll, not a whole winforms app.
So, here is what I have done so far:
Made a class library project
Added a custom control object
Confused myself badly
Googled it, to no avail
How can I control the component? For example, I want my component to not have a visible design view, I want it to stay below like the stopwatch component and the notifyicon component and such, it is not something to be designed. Then, how do I edit the possible properties a user can control, and make them effect the end result? What do I place the code which powers the component on? The class library file, or something else?
Thanks for your help! I have a whole set of components I am going to create, this will get me going much faster than trial and error.
I think you may want to check some walkthrough on how to create components. Such as this one: Walkthrough: Authoring a Component with Visual Basic. Once you are done with that one, there are more walkthroughs on various related topics, such as how to use design-time support, implementing designers and so on.
OK... This is a really abbreviated example. You should start by basing yous off of an existing .net component.
Public Class MyControl
Inherits DataGridView
'...add your properties/functionality...'
End Class
Then compile the DLL, and add it as a reference to whatever project you are working on. Once added, you can add the controls in the DLL into your toolbox.
This has more instructions on how to modify a UserControl (slightly different from the one above, but it explains well. This is a general explanation.
#comments -
Yes, there, are things that will do what you want. Start with a class that inherits Form instead of DataGridView in the example I gave you, and the changes described in the links provided.
"Your properties and functionality" is whatever you want to do that the base control does not do.