What to do when a form's class becomes too large? - c#

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.

Related

The opposite of events and delegates?

This might sound weird, but I am just experimenting with the thought of it. I was wondering about subscribing functions to different classes. So i have a base or static location where my method is held, and without relying on inheritance, am i able to subscribe that function to an object?
For example:
Action class has a method class SendKeys
I have three objects called Textbox and Button and Textarea
Realistically i don't want them all to have access to SendKeys function, just Textbox, and Textarea. But i also don't want to copy paste the SendKeys code over and over again.
I could create a static class that takes the data and the two objects will call that static class, but that just seems like extra work and i would be creating the function anyways in order to call an external function.
The best solution i have is to just copy paste code. but i was wondering if i could subscribe specific functions. Its like the opposite of what an event and delegate can do right? Cause the subscription requires code in the class of the subscriber. I kind of think i want partial classes? I am not sure. Thoughts?
A deeper dive into the issue:
I have a bunch of different elements to work with here are some basic ones, it goes deeper when you take into account custom elements:
Button
Textbox
Textarea
MultiSelect
SingleSelect
RadioButtons
Checkboxes
MenuItems
PasswordTextboxes
ETC
Each one of these would have their own actions that can be applied. For example they all would have the same properties like GetAttribute or GetCssValue but i don't want to be sending keys to a checkbox, so i dont want to have the ability to have that function when creating inheritance. BUT, i do want other objects to have those functions. The code is lengthy and a bunch of copy pasting code is ugly. I was hoping i can subscribe functnions to objects. So i can say something like Actions.Click(Textbox) or Textbox.Click or w.e but i cannot do Actions.SendKeys(button, "fdsaf") or Button.SendKeys("fdsaf")

C# moving auto generated code to better structure code

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.

Calling Usercontrol method from another form

I have this Usercontrol with a Listview loaded in the Mainwindow:
<Controls:MetroAnimatedSingleRowTabControl Grid.Row="1" x:Name="MainTabControl" Controls:TabControlHelper.IsUnderlined="True" Margin="10,0,0,1">
<TabItem Controls:ControlsHelper.HeaderFontSize="40" Header=" List" Foreground="#CCB5BABB" Controls:ControlsHelper.HeaderFontStretch="UltraExpanded" HorizontalAlignment="Left" VerticalAlignment="Top" >
<load:Usercontrol1 DataContext="{Binding}" />
</TabItem>
From this Usercontrol a ButtonClick calls another form for entering new data. After saving the data to database, I call a method loading the list in Usercontrol by referencing the entire Usercontrol to the entry window :
private readonly Usercontrol1 temp;
public newDataEntry(Usercontrol1 temp2)
{
InitializeComponent();
temp= temp2;
}
private void buttonentry(object sender, RoutedEventArgs e)
{
temp.fillList(); // list in Usercontrol fill
this.Close();
}
Since I want to use the same entry form with different Usercontrols, is there a more effective way to call method in Usercontrol?
Without a good Minimal, Complete, and Verifiable example that shows clearly what you are doing, why you want to call this method, what the method does, and what specific problem you are having generalizing the action, it is impossible to know for sure what the best answer for your scenario is. That said, some discussion can be provided.
First and foremost, it is a mistake for your newDataEntry class to depend on the Usercontrol1 class at all. This should already be apparent, due to the issue you are running into trying to reuse it with other UserControl classes, but it is also a basic OOP concept: a class that exists to support some other class should not itself carry a dependency on that other class. Doing so breaks reusability in a way that is fundamentally opposite a primary goal of OOP.
So how do you get rid of this dependency? Well, the most general way in C# would be for your Usercontrol1 to subscribe to the newDataEntry object's Closed event. Then it can do whatever it wants at that time, including calling its own fillList() event.
Of course, if the newDataEnty window is used modally (i.e. you call ShowDialog()), then subscribing to the Closed event is overkill. You can just call whatever code you need to when the ShowDialog() method returns.
All that said, the name fillList() hints that you're copying list data directly into some list-based control (e.g. the ListView you mentioned). When in fact, in a WPF program, you should be manipulating only view models and letting the UI respond accordingly. Again, without a good MCVE showing context, it's impossible to say for sure that's what you're doing, never mind provide any specific advice along those lines. Suffice to say, it's likely that this code doesn't belong in the Usercontrol1 class at all.
See also these related posts:
How to call method of the main WPF window from the modal window? - this seems most applicable. Unfortunately, the accepted and top-voted answer is one of the worst (introduces exactly the kind of class coupling you're trying to avoid here), but there are other answers with some useful information.
WPF MVVM call ViewModel Save method on Window Close - this discusses doing something similar in the context of using a proper view model. May or may not be directly applicable to your scenario.
Communicate between two windows forms in C# - this is about Winforms, but in this particular scenario the basic techniques are similar. In this particular case, you wouldn't need to declare a new event, because the Closed event already seems to do what you want.

Different functionality in a single object situationally (Xna, Menusystems, and general C#)

I've been wondering a lot how to have an object act different situationally.
To clarify what I'm wondering:
I want to make a menusystem, and I want to have a "button" class. But the button should behave different depending on what kind of button it is.
One button may close to program, another may start the game, a third may enter settings.
(I was thinking of parsing methods as arguments, but then you still have to write a lot of different methods somewhere in your code)
How do you do this with OOP in mind? I could hardcode the very basic functions of a simple menu using enums and switchcases, but I would want to know if it could be avoided.
I want to avoid things like delegates because games aren't eventbased in such fashion, and also switch-cases, large if/else statements because they are really ugly.
Is there a way to make objects behave like this?
What are other alternatives to making menus, trying to avoid the switch-cases for the commonly used enum. (Not disallowing enums)
I want to avoid things like delegates because games aren't eventbased in such fashion
Aren't they, though? A button click is an event, regardless of whether or not it's a game or a web application. It's by definition something happening that you'd like to react to, such as a button press. What happens when a button is clicked should be loosely coupled from the button in the UI, for the reasons you already encountered (large switch/if-elses are a pain) among others. A C# event field seems like the perfect fit, for this particular case anyway.
At some point, you create the settings button, somewhere, somehow. Why not wire up the event there? Something along the lines of:
class Button
{
public Button(string label) {}
public event Action Clicked;
}
class Program
{
public static void Main(string[] args)
{
var settingsButton = new Button("Settings");
settingsButton.Clicked += () =>
{
// open settings view
};
}
}
I'd avoid things like inheritance for this problem as it adds unnecessary complexity for the wrong reasons. You should (probably) use inheritance if the overriding class changes or supplements the behavior of the class it extends (a logical progression would be object extended by Component extended by Button extended by ToggleButton) but not to create a class hierarchy that's very much tied to how your UI is built up. If you change settings access to a dropdown menu instead of a button press, you don't want to be tied to a SettingsButton class; you want to be simply able to change which event triggers the desired behavior, in this case pulling down the dropdown menu.

Should I just make sure a value is within its range during a main loop or fix it when it supposedly changes?

Currently I have this code all throughout my program in many places such as form resizing events, splitter moving events, document size changes, et cetera:
hsc.Value = (int)MathHelper.Clamp(hsc.Value, 0, hsc.Maximum - hsc.LargeChange + 1);
vsc.Value = (int)MathHelper.Clamp(vsc.Value, 0, vsc.Maximum - vsc.LargeChange + 1);
I'm wondering whether or not it would be better to just put it in a main loop because my program has a drawing code that is called whenever the application goes idle (very often).
The disadvantage of having this code in events is because it is code repetition and I might miss an event. The disadvantage of having it in the loop is that it may not be needed each loop and it is wasted processor cycles. However, it may be premature optimization because it probably would not be noticeable to the end-user.
What framework are you using? (WinForms, WPF, Silverlight, etc)
If it's in every Window / Form / View / UserControl then you might consider putting this functionality in a base class and pointing all these events to event handlers in the base class.
Neither of your solutions seem correct - you shouldn't be redrawing in a 'main loop' if nothing has changed, and you shouldn't be copy/pasting duplicated code throughout your app.

Categories

Resources