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.
Related
I have 2 problems:
"Which Button called this form?" (short version)
I can not touch the button or button's form
Why do I want this?
I have many forms and need to know how the user got there. If I could get the Form (not the button) it may also solve the problem.
Long version: I need to copy some properties of source form/button to the new one without do it manually and I intend to use it later on Exception reporting to catch more info
Initially, i tried to do a "newForm.Caller = this;" on each button but there are 200+ forms and lots of buttons on each.
All forms and it's buttons are custom controls so I can do things there.
Tried things
I tried to do things with StackFrames and reflection at form constructor but don't work (889310)
I found this 10401190 for JAVA but it can't help
I thought I could use the OnClick override to store the last button instance in a static place in buttons/forms class then get it in the form constructor but seems to be the worst solution. (Many things open forms and the culprit would be the last button pressed)
The problem get worse when other things open Forms and I lost the reference (DataGridVewButton, timers, linked label, ...)
EDIT1: (oɔɯǝɹ)
Another detail, forms can be called from external Plugins. So again I don't have acesses to the code to change it.
EDIT2: Example (Graham Bass,ShreyasKapur)
FormA has a ButtonA that when clicked shows FormB
FormA inherits FormBase
Button inherits ButtonBase
FormB inherits FormBase
I can NOT change FormA neither ButtonA codes, only FormBase and ButtonBase codes
Edit3: (Bradley Uffner)
ShowDialog() forms have the Owner property that solves part of the problem. Thanks Bradley, I forgot about that!
Unfortunately, all existing code uses the parameterless constructor.
"Displays this form as a modal dialog box with no owner window" (1)
I would think that you are trying to solve the wrong problem.
When your forms are this interconnected, you coupled them to tightly. By coupling them even more tightly by looking back to who called you, you are only making you problem worse. See also: the comefrom instruction.
I would suggest passing parameters between your forms to supply them the data they need. But keep the number of parameters to an absolute minimum, and don't try to use something like caller, that would be cheating.
My goal
I am working on a project in C# using Visual Studio 2013. The project is one that I intend to contain a lot of pages. These pages are all linked together using buttons. My problem is that I cannot come up with an efficient and elegant solution for this.
My attempts
So far I have came up with two potenial solutions to my problem. First I added extra forms and then on button press I hid the current form and displayed the new form, like so:
Form2 frm = new Form2();
frm.Show();`
Form1.Hide();
While this does work, I have two problems with it.
My project will end up with hundreds of forms
The transition between forms looks sloppy. I am aiming for a browser like transition by where all navigation occurs on one window, without opening and closing others.
The second potential solution I tried incorporated the use of Panels. So I essentially created each page on a different Panel. Then the appropriate panel was shown upon a button press and the rest were hidden. Like this:
private void button1_Click(object sender, EventArgs e)
{
mainMenuPanel.Hide();
submenuPanel1.Show();
submenuPanel2.Hide();
submenuPanel3.Hide();
submenuPanel4.Hide();
}
This is exactly what I was looking for however my issue with it is that managing the vast amount of panels quickly became a nightmare. Editing the controls on a Panel that was hidden behind 9 other Panels and as the number of panels in my project was only going to grow - this does not seem like the ideal solution in its current form.
In my head I thought there maybe an option in Visual Studio 2013 that allows me to 'hide' the Panels I am not using on the form, or drag them off the form temporarily. Is that an option in Visual Studio.
If not do any of you know a more efficient and manageable way of achieving this?
Thanks in advance.
If you are stuck using WinForms, your best bet is probably using UserControls. you can actually extend the UserControl class out to be a "page" ie: UserControlPage. This makes the form much simpler in function, but you will need to do some finicky work with handling events /passing data if the controls need to talk to each other.
if you aren't nailed into using Winforms, WPF supports all of this natively, and has wonderful tools for building all the pages you would need, and storing/populating your data, and propagating events.
If you want to have single form with changing content, and you don't want to mess up with panels in one form, then solution is user controls. You will be able to create them dynamically and add to form controls. Also there is no mess, because your form will be very simple - you can have single 'placeholder' control which will be used to dock user control which is currently displayed (e.g. panel control):
private void ShowContent(Control content)
{
placeHolderPanel.Controls.Clear(); // clear current content
placeHolderPanel.Controls.Add(content); // add new
content.Dock = DockStyle.Fill; // fill placeholder area
}
Usage:
private void button1_Click(object sender, EventArgs e)
{
ShowContent(new FooUserControl());
}
You could subclass the Panel class and create as many of those custom panels as needed, then they would be inserted on your Main Form, and managed as you described.
The advantage is that you would be able to individually edit them as a separate user control.
The drawback is that you lose direct event handling of controls on those panels from the main form. You can still define your own events on those panels and delegate the individual control events.
There's always a trade-off somewhere.
Cheers
I have written a C# 4.0 Windows Forms Application that creates two panels which are both populated exclusively with text labels. I would like to add functionality to my application to print these panels exactly as they appear on the form, but I only want to print these panels and their contents, with no background or other parts of the form.
This link was especially helpful as an overview, but so far I'm only able to print what amounts to a screen capture of the form. The entire form is included, buttons, trim, background, and all. It looks like I need to "rebuild" the form by creating a graphics object (I use the term generically, as I'm not sure what specific graphics-related class I need to employ) and somehow transfer the contents of the panel into this object.
My question is: what classes and/or methods should I research in order to build this graphical object? Also helpful to know: are there any handy tricks within the .NET framework or any libraries out there to automatically fit the result to a single page when building the PrintDocument object?
OK, I found one way to do it (love to my Perl bros out there):
Wrap both panels in another parent Panel. Let's call this Panel "parentPanel." Create a bitmap (memoryBitmap)that is the size of parentPanel (parentPanel.Size).
Next: parentPanel.DrawToBitmap(memoryBitmap, new Rectangle(parentPanel.Location, parentPanel.Size)
Then, in the print page event handler: e.Graphics.DrawImage(memoryBitmap, 0, 0)
I'll leave this open in the likely event that someone else has a better idea.
Currently my main form has a ton of event handlers because there are a lot of controls. It is very similar to a paint application. I have condensed it down quite a bit and I am sharing event handlers whenever possible but the class is still around 1,000 lines of code. I realize that may not be much to all of you but it is considerably larger than the rest of my classes.
I have refactored a lot of code to other classes but all those event handlers still increase the line count by a large amount. I also started using region blocks to separate event handlers in to groups and that is working rather well but I still would like to know SO's opinion on the matter as to best organize a large amount of form event handlers.
Edit: So I've been using partial classes and I must say, I don't really like them that much. I'm not sure what to do at this point.
I may go back to using region blocks as I'm not sure user controls will help my problem at all. Honestly I did not mind the region blocks that much. That class was the only place I used them and it organized the different sections of the code quite nicely (Menu Event Handlers, Toolstrip Event Handlers, Drag and Drop Support, et cetera).
Still, if anyone still has any other ideas or would like to elaborate upon any posted thus far I'd be more than appreciative as I am still looking for a better solution to this problem.
1000 lines of code is nothing, and that should not be the basis for refactoring your code. Refactor your code where it makes sense; not just because a class contains more lines of code than your other classes. Some classes will require more code than others, and that's perfectly okay.
That being said, if it makes sense you can divide the controls into logical sections, and put them in user controls. Make sure that there is a good justification for doing so though, because otherwise you'll only be convoluding your code base.
I must remind you again though, don't split your code up just to reduce the lines of code.
You could either split the functionality into separate classes (e.g. creating UserControls like Ed has suggested), or think about using partial classes (where one class can be split among many files). I have found partial classes handy to group together related chunks of code, when the "main" class file is getting to large. Sometimes this is the first step in refactoring those chunks of code into separate classes and/or controls.
It's hard to make a concrete recommendation without seeing the code, but those are some of your options.
If you haven't already (you don't mention it) I would split out the various individual controls into UserControls. You can handle all of the events from within the UserControl class and only expose those events that the parent form must absolutely handle. These will likely be small in number and will drastically reduce the responsibilities of your main form.
For example, each tool button could live inside of a UserControl. The canvas control can maintain and instance of the tools control and so on. You can keep creating the composite controls where each upper layer becomes less complicated and most of the actual logic is handled below it.
I would suggest of using more OOP solution. Do not add UserControls, as you add more *complexity*. Let's try to maintain complexity you already have, but make things more clear, cause this is what really you're asking for, I believe.
DI like. In practise if you need to handle a lot of events for a lot of contorls, create ControlManagers, which accepts in ctor the control and subscribes to its events.
So for every control you will have it's own manager.
Advantages:
Clear separated code in different classe, so easy recognizable in case of problems and my be more clear from architectural point of view.
You don't break down your architecture with a lot ot delegated events between tons of controls and subcribers (one subscriber per control)
Sure you will need organise, by the way, the data flow between different classes. But it's by my experience, haven't to be a big problem.
EDIT
An example pseudocode:
UserControl1 mycontrol1; UserControl2 mycontrol2;
public class MyControl1Manager {
public MyControl1ManagerFor1 (UserControl1 uc1) {
//subscribe to events of uc
// here all code to handle events
}
public MyControl1ManagerFor2 (UserControl2 uc2) {
//subscribe to events of uc
// here all code to handle events
}
}
and somewhere in code:
MyControl1ManagerFor1 controlManager1 = new MyControl1ManagerFor1 (mycontrol1);
MyControl1ManagerFor2 controlManager2 = new MyControl1ManagerFor2 (mycontrol2);
Something like this.
Hope this helps.
Once I had a form that became really big. It showed the same information in many various ways. To reduce number of code in single file I used an approach similar to UserControls. All the GUI elements were placed on the form, but their initialization and handlers were maintained by helper classes. They were equivalents of UserControls, but without GUI interface. These classes were initialized in main form's constructor:
SideViewHelper sideView = new SideViewHelper(parentForm, gridControlMaster, gridControlDetail, buttonSubmit);
All the logic that handles the gridControl events, button events are handled inside the helper class.
After the initialization the main form (parentForm) may change state of many UI items by single call of ViewHelper's method.
These classes are created for this only form and are as lightweight as possible.
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.