Looking at the source code for a windows form application, the class declaration states its a partial class. I understand that this means there are parts of the class in different physical files.
The code in MyForm.designer.cs doesnt appear to have a constructor or any means of generating the form. So my question is, where do i find the rest of the code for my windows form?
The constructor for MyForm is in the main MyForm.cs file. Because it is partial, the constructor can reside in MyForm.cs, and the generated code can stay in MyForm.Designer.cs, allowing for separation of generated and developer-created code.
Use the View Code option to see the actual source of MyForm.cs, which has a constructor as well as all of your code.
MyForm.cs has the constructor and MyForm.designer.cs has the function private void InitializeComponent() which will be called from the constructor (in MyForm.cs).
In private void InitializeComponent() your components will be created and initialized.
Using Partial keyword code can be reside in multiple classes.When you add a window form that creates three files 1. Code file(.CS) 2. Designer file(.Designer.cs) 3. Your Design part. All used Partial keyword.
If you want to see code then double click on design form you will direct to code file there you can find the code and you can handle all the code and events(Developer's Code) like constructor and all.
In Designer.cs you initialize the controls their control properties.It's system generated code but still you can modify.
Hope this helps.....
Double click on the form will take you there.
Related
I have 2 forms that inherit a control from the class below:
public class AInbox: Form
{
public FlowLayoutPanel InboxItems;
}
The forms inherits as such:
public partial class Inbox : AInbox
{
...
}
In the Designer.cs file i commented out the original "InboxItems" control declaration and everything compiles and runs fine... except the GUI designer. When i open the Designer I get the error "The variable 'InboxItems' is either undeclared or was never assigned."
Is there any way to use this inheritance and still have the designer work?
I'd recommend against inheriting a form with generated code (like you're doing with Inbox).
If you want the child class (Inbox) to add additional controls, I wouldn't use the designer directly on the child class, because I don't think the visual studio form designer will play nicely when half of the form was designed in the parent class. If you need to reuse certain parts of your form in a different form, you might want to consider moving that part of the form to a separate user control. You can use the designer on this user control and later put the user control in the forms.
If you just need to have the same form, keep an instance of the form in your other class. Move your logic away from your form (view) and in your other class (controller).
I am pretty new to C# and wondered if there was a simple way to move the auto-generated code to a separate class file?
For example, if I create a windows form onto which I drag a button. Then if I double click the button it auto generates a click event handler under the main Form1 namespace and class. Is there a way that I can move this code to a separate file (maybe a class.cs file) if I want to structure my code in a neat way rather than having an ever growing main??
All of the quick and dirty 'Hello World' style C# examples just show you how to add items to the form in the way described above... they don't seem to go into best practises on how to structure large code developments where structuring code into separate files can beneficial. Is what am am thinking of necessary or do developers use the standard click handlers (left in the main form) and then use that to call external reference files containing the classes/methods???
I'd be interested if you guys can steer me in the correct direction on the best practices people use to structure large C# form based projects
Many thanks
Michael
Yes, you can move the event handlers to a "separate" class. You already have two files: Form1.cs and Form1.Designer.cs, each of which contain a partial class. At the top of Form1.cs, you will see:
public partial class Form1 : Form
You can create a new file (called whatever you like) and add in the following:
public partial class Form1
{
}
You can now move any of your event handlers for Form1 into this new file.
All that said, we've got a suite of 4 Winforms applications totalling about 450 controls, and we've never done this. The most buttons we've had on a form where we use the designer to create the event handler is about 10. Once you have a lot of buttons (such as in a menu), you are much better off not using the designer, and creating the items (and their event handlers) by code.
You will also not end up with one form that contains tens of thousands of lines - instead you will create individual controls which contain isolated logic, and then tie these together on the Form.
I have a number of propertied in a class that creates a pdf document that need to be set before the pdf is created. This class is named generatePDF. I would like be able to change the properties using a form and persist the properties.
INotifyPropertyChanged was implemented in the generatePDF class. I used the Data Source Configuration Wizard (Open DataSources vertical tab on the far right side of the screen , click the upper left icon to add a Data source) to bind the GeneratePDF class. Now in the Datasources windows I can see all the properties and can easily drag them onto a configuration form.
I have a method in the generatePDF class that puts initial values into the properties. I ran this method before showing the configuration form.
When the configuration form is shown the textboxes that I would expect to be filled with the initial values are blank. When I enter a value that should change the property in my GeneratePDF instance, the property is not changed. In addition, there is control automatically added to the configuration form that apparently allows the user to step through different instances of the GeneratePDF class -- like rows in a database table. The configuration form doesn't appear to be bound to the single instance of the GeneratePDF class.
I tried to change the GeneratePDF and all the properties and methods of the to static, but when that was completed and error "... can't implement INotifyPropertyChanged on a static class..." was shown.
I'm guessing I'm not the first one to experience this problem but I was unable to state my question clearly enough so that a google search would find an answer or a tutorial.
I'd appreciate help binding a specific instance of a class to a configuration form.
OK, I've been working on this all day, and I think I've found a solution.
When I added the project data source GeneratePDF, a ??what does microsoft call this?? 'GeneratePDFBindingSource' was added to the project. I went ahead and drug all the properties from this class onto a configuration form.
I modified the constructor of the configuration form to the the instance of GeneratePDF as a paramter.
The constructor is also modified. After Initialize Component runs, the configuration form binding source is just a 'typeOf' GeneratePDF. The DataSource property of GeneratePDFBindingSource was updated to point to the instance which I just passed in.
However, when the form was displayed the values STILL were showing blanks. I looked at the system generated code for the configuration and noticed that there was an EndEdit() method that could be called when changes were completed. Adding this to the constructor and... it worked!
So below are the few simple lines of finished code. I'm posting this answer in case others happen upon this question, or if I forget how to do this at some time in the future and need a reference.
namespace com.myCompany.myApp
{
public partial class frm_Configuration : Form
{
public frm_Configuration(GeneratePDF generatePdf)
{
InitializeComponent();
GeneratePDFBindingSource.DataSource = generatePdf;
GeneratePDFBindingSource.EndEdit();
}
}
}
I need to create a non-visual component, FooComponent, that will do some management for all controls of type Bar that resides in its form.
I have the following constraints:
The FooComponent can only be added to forms.
Only one FooComponent per form is allowed.
FooComponent should register to the form closing event, and when it fires and to some function on all Bar's and sent the e.Cancel value based on the returned values.
#1 and #2 above should be enforced on run-time as well as design time.
#3 event registration should be made automatically and not by the FooComponent's users.
I searched Google and MSDN for some help and read about Component and ComponentDesigner classes, but I didn't find anything for the rescue.
What should I do?
(1) To control that the component can only be added to a form, use a FooComponent constructor that is passed a form, and don't define the default constructor. It's called like:
FooComponent component = new FooComponent(this);
where the component is created from within the form itself. By not-defining the default constructor, this:
FooComponent component = new FooComponent();
will not compile.
(2) Expose a FooComponent property on the form itself, and in the constructor of the FooComponent, set the passed form's FooComponent to this.
(3) Same thing, in the constructor for the FooComponent, register with the closing event for the form you passed
Put it all together and you get:
public class MyForm : Form {
public FooComponent OwnedComponent { get; set; }
}
public class FooComponent {
public FooComponent (MyForm OwnerForm) {
OwnerForm.OwnedComponent = this;
OwnerForm.FormClosing += MyCallback;
}
private void MyCallback(object sender, FormClosingEventArgs e) {
...
}
}
EDIT
Unfortunately, if you need the default constructor, and if it has to be a true drop-on-the-form Component, there's no way to enforce that a component is only created on a Form, or that the Form only has one instance of the component (not from within the component, anyway).
The problem is twofold:
(1) Dropping a component doesn't add the component to the form, it adds it to the form's components collection. So even if you could get a handle to the parent/owner, it will never be a form.
(2) As Neil pointed out, dropping a component onto a form calls the default constructor, which passes no parameters, and, of course, none of the component's properties (such as site or container) are populated.
Possibly helpful: A component can be designed to be notified when it is created in a couple of ways:
(1) By implementing a constructor that takes an IContainer parameter. When the component is dropped on a form, the generated code will call this constructor, instead. However, it will only do this at runtime, not design time. But the container will be a handle to the form's components collection.
public FooComponent(IContainer container) {...}
(2) By implementing ISupportInitialize. When the component is dropped on a form, the generated code will additionally call BeginInit() and EndInit(). In EndInit(), you can access properties such as the Site and Container. Again, you'll only get this at runtime, not designtime, and throwing an exception here won't stop the component from being created.
Old, but excellent articles on Components and Controls from MSDN Magazine by Michael Weinhardt and Chris Sells.
April 2003 Building Windows Forms Controls and Components with Rich Design-Time Features
May 2003 Building Windows Forms Controls and Components with Rich Design-Time Features, Part 2
These are now .chm help files. You will need to unblock in the file's property page to enable reading the contents after downloading.
I don't think it's possible to define exactly what a contained class can be contained within. I've certainly never seen an instance where I've gotten an error (or even a warning) for setting up a property of one type in another, even in WinForms.
Something you might be able to do is to define a Form-derived ancestor for your forms that contains a reference to your (internally-visible) FooComponent, initializes one on instantiation, and attaches the handlers. For best results it should be parameterless and the only constructor overload, so it forms the base for any constructor your consumers come up with. Then, just make it a house rule that forms derive from your ancestor class and not directly from Form (you might be able to use a code inspection tool like FxCop or similar to enforce this when code is committed to source control). Your users now get a FooComponent in every Form they create, cannot create their own (it's internal and should be in another project with your Form ancestor) and don't have to do anything other than derive from the new class to make their forms behave the way you want.
You are asking for a lot. In general, making components aware of the form they are dropped on is quite difficult. This answer can help you get the event handler implemented. You'll need to implement ISupportInitialize to get the EndInit() call to setup the event handler.
Preventing multiples is quite hard too, I can only think of a custom designer that can step in early enough to prevent the 2nd one from being added.
What does InitializeComponent() do, and how does it work in WPF?
In general first, but I would especially be interested to know the gory details of order of construction, and what happens when there are Attached Properties.
The call to InitializeComponent() (which is usually called in the default constructor of at least Window and UserControl) is actually a method call to the partial class of the control (rather than a call up the object hierarchy as I first expected).
This method locates a URI to the XAML for the Window/UserControl that is loading, and passes it to the System.Windows.Application.LoadComponent() static method. LoadComponent() loads the XAML file that is located at the passed in URI, and converts it to an instance of the object that is specified by the root element of the XAML file.
In more detail, LoadComponent creates an instance of the XamlParser, and builds a tree of the XAML. Each node is parsed by the XamlParser.ProcessXamlNode(). This gets passed to the BamlRecordWriter class. Some time after this I get a bit lost in how the BAML is converted to objects, but this may be enough to help you on the path to enlightenment.
Note: Interestingly, the InitializeComponent is a method on the System.Windows.Markup.IComponentConnector interface, of which Window/UserControl implement in the partial generated class.
Looking at the code always helps too. That is, you can actually take a look at the generated partial class (that calls LoadComponent) by doing the following:
Go to the Solution Explorer pane in the Visual Studio solution that you are interested in.
There is a button in the tool bar of the Solution Explorer titled 'Show All Files'. Toggle that button.
Now, expand the obj folder and then the Debug or Release folder (or whatever configuration you are building) and you will see a file titled YourClass.g.cs.
The YourClass.g.cs ... is the code for generated partial class. Again, if you open that up you can see the InitializeComponent method and how it calls LoadComponent ... and much more.