Split a large winform class - c#

I'm using WinForms to design an application. It has many controls (buttons, menus, etc) that have underlying event handlers. I find that my class is getting rather large and hard for one person to navigate. This is due to the fact that each control requires one or more methods to handle events within the context of the window.
What are some techniques for organizing these methods or splitting up such a large class?

If it is just about navigation you can split your class in several files, just add the partial before the class declaration in every file.
Generally if you have some very complex controls or event handlers bound to these controls it can be reasonable to separate those in your own custom user controls and just add them to your form. Just add a new user control element to your project and customize it the way you need.
All your controls are immediately available as any other .Net controls in the same project, but you might also want to put them in a separate DLL file (if you want even more separation of your code).
Here is a nice tutorial how to design your own controls in WinForms.

Related

Templated Control vs Custom Control in UWP. No clear answer found online

In my UWP app, my control options are User Control and Templated Control. My understanding of a User Control is KIND OF clear at this point.
I was told that a Custom Control's style/template is only instantiated in memory once, and that this only happens at the time the control is first used. That's what I want since I know the control I am creating will be used in a ListView.
In the book, XAML Unleashed, however, the author creates his Custom Control by starting with a User Control, and then simply changing it's base class. The thing is that the control he created calls InitializeComponent(). I hear that this type of class uses more memory because it is re-instatiated for each item in the ListView.
Also, I never thought that Custom Controls used the InitializeComponent() method. I thought there was simply a call to this.DefaultStyleKey = typeof(MyClass); in the constructor. What gives? I am confused on what is what...
And last, why is the style/template of the Templated Control placed in the global Generic.xaml file, instead of its own separate file (i.e., xaml file and a code-behind file pair)? If the control is supposed to be custom and "portable", then shouldn't it be totally separate from other code? I haven't found a single article explains any of these things in detail on any level.
This is something most people get wrong so I'll try to clarify a few things for you.
Memory
The whole memory thing, it's all in the Visual Tree. When you instantiate any control, whether templated or UserControl, you will use up memory with every instance because in both cases you are creating a full copy of the visual components in the template.
The templated control will create a copy from the ControlTemplate while the UserControl parses the XAML file when InitializeComponent() is called.
Memory usage will be the same if you create 100 templated controls or 100 user controls if their content is the same.
Usage
Templated controls are best for situations where you're creating a single component, like a Button, Slider, MyStarRatingInput, etc. and you're giving the users of your control the ability to swap out the template with their own. It takes a lot more effort to do this properly than UserControls because the logic has to be template agnostic and your templates have to react properly with visual state changes.
A UserControl is best for layout or views, like forms, popups, screens, pages, etc. You will not give someone the freedom to tamper with the content of your view. You may expose a few public/dependency properties if some views are reusable in a small way, but generally they are set in stone.
Generic.xaml
I honestly don't have an answer for this. Microsoft should've allowed multiple resource dictionaries to enable cleaner partitioning of control templates. Generic.xaml is a reserved filename that referencing projects will look for as the root source of the base styles of your controls. You could reference other XAML files from Generic.xaml, but that's annoying and it bloats the root of your resource dictionary. For now, you're stuck with this method.
Recommendation
If you're sharing a control library, you would want to use templated controls as much as possible. If you're building controls, views, pages, etc for your current project and they're not meant for reuse, then use UserControls.
You can still create a UserControl in your control library if you plan on owning the template and forcing all users to accept your design.
I also recommend templated controls for items that you plan on instantiating a hundred times in a single view, like a ListView. You will see noticeable speed improvement if your template is preloaded into memory instead of parsing a XAML file on every instance.

WinForms UI design: displaying controls for only currently viewed hierarchy level

I am attempting to create a WinForms application which allows the user to display and edit data stored in a MSSQL database. The data being altered is hierarchical, and within a single level of the hierarchy the properties which may be altered are identical; in other words the controls for a single level of the hierarchy are the same, but they may differ from other levels.
I am trying to create the application in such a way that there is only a single form with controls that update based on the hierarchical level of the item being viewed by the user. I realize this is possible by putting all the controls for all levels on a single form and updating their 'Visible' property, but that method makes design of the form difficult due to clutter... Have any of you found a more elegant/less ugly solution?
If you want to do this in WinForms, you can take advantage of the fact that visibility and enabled-ness are both "heritable" traits in the Windows model.
In other words, if you group all of your controls within a parent container (such a Panel or UserControl), then disable that container control and make it invisible, all of its child controls will also become likewise disabled and invisible.
I recommend creating UserControls for each level of the hierarchy. The line of thinking is pretty much the same as if you used separate Forms, except that they're not actually separate Forms. Multiple UserControl objects can be displayed on a single form, so you can have as many as you need. This keeps all related controls together, which makes management much easier. You can also interact individually with these UserControls in the WinForms designer, just like they were separate Forms, solving the "clutter" problem.
To toggle between "active" hierarchies, loop through all of your UserControl objects. Make the currently "active" one enabled and visible (all of its children will automatically become likewise). Make the rest of them disabled and hidden (and all of their children will automatically become likewise).
I won't argue with HighCore here, though. If you don't already know WinForms, you could just as easily spend your time learning WPF. If you decide to do so and want to know how to accomplish this same task in that UI framework, please be sure to ask a new question.

Winforms: TabControl-based Wizard with steps in separate classes and designer support

I am trying to build a wizard by using the TabControl component.
It works fine, but I end up with so many pages (tabs) that having all the components and event handlers in one class makes it unreadable.
I now have this idea of declaring each step of the wizard in a separate class which extends from TabPage, then adding those steps to the wizard screen class (which extends from TabControl). How do I do that and still get designer support in the steps?
Simply extending TabPage doesn't enable designer support.
Thanks in advance.
I would suggest splitting your business logic from your UI logic. Create UserControl derivatives for both the contents of each TabPage as well as the TabControl itself. It's a lot easier to manage this kind of code if the UI logic is separate from the business logic. You would probably benefit from creating a class for each tab, and a class that manages all the tabs. Hook these classes up to the UserControls that are on the TabPages and the TabControl.

What are the purpose of User Controls in Visual C#?

User Controls -- Do they serve a special purpose?
As far as I can tell they are no different to forms - they have the same toolbox and features.
Are there certain times when they are appropriate to use over forms?
It would be interesting to understand what they are good for.
You use them to group a set of controls and behaviors together in a re-usable way. You can't show a control on the screen unless it's added to a form somewhere.
One good example is a textbox. It's very common to have a label next to your textboxes. You can build a user control to make this easier. Just drop a label and a textbox on the control, expose whatever your properties you want, setup the new control in your toolbox, and now you can just drop this control on your form instead of needing to arrange a label and a toolbox on the form separately.
You could kind of think of them as a panel which "remembers" what controls you put on it. And there's one more important piece. You can put code in these controls as well, and use that to also build special behaviors into your custom controls.
I have to disagree (slightly) with the selected answer. Reusability is only part of what a UserControl is for.
All Controls are reusable. Almost all controls are reusable on the same Form/Window/Panel/etc. For example, a TextBox is a control.
There are two ways to create your own reusable control:
Custom Control
Completely custom, and reusable.
Created entirely in code.
You get a bit more granular control over what your control is doing this way.
Lighter weight (usually), because there isn't anything added in for designability within Visual Studio.
In ASP.Net only: No "HTML" type file to use or edit.
User Control
Completely custom, and reusable.
Created partially in a designer in Visual Studio, and partially in code. (via code behind)
Much easier to deal with from a visual aspect.
A little heavier, as there is pre-existing code added in by the framework to support designing inside Visual Studio.
In ASP.Net only: You can change the appearance a bit simply by editing the .ascx file (basically HTML).
User Controls serve the purpose of reusing controls.
Imagine you need a search box in several pages of your application. You can create a search user control and drop it in every page where you want it visible.
So, it's nothing more than a container that aggregates reusable blocks for your pages.
Forms have a lot of extra furniture that you don't need if you simply want a collection of controls together - the minimize and maximize buttons for example. If you just simply grouped your controls in a Panel, you'd have all the event handlers on the same form as the panel - with a user control, the event handling code is in the user control class, not the form class.
You can reuse the same control on many forms. In fact all items you are using while creating windows forms are the controls. User controls are just extra controls extending controls library provided by .NET.
In ASP.NET, user controls enable you to split your page into reusable components. For example, you may want to have a search box which can be used in different places on your website, so you'd use a user control. They can also be used for partial page caching. You can cache portions of your page to improve performance.

How to create a tree-view preferences dialog type of interface in C#?

I'm writing an application that is basically just a preferences dialog, much like the tree-view preferences dialog that Visual Studio itself uses. The function of the application is simply a pass-through for data from a serial device to a file. It performs many, many transformations on the data before writing it to the file, so the GUI for the application is simply all the settings that dictate what those transformations should be.
What's the best way to go about designing/coding a tree-view preferences dialog? The way I've been going about it is building the main window with a docked tree control on the left. Then I have been creating container controls that correspond to each node of the tree. When a node is selected, the app brings that node's corresponding container control to the front, moves it to the right position, and maximizes it in the main window. This seems really, really clunky while designing it. It basically means I have tons of container controls beyond the edge of the main window during design time that I have to keep scrolling the main window over to in order to work with them. I don't know if this totally makes sense the way I'm writing this, but maybe this visual for what I'm talking about will make more sense:
Basically I have to work with this huge form, with container controls all over the place, and then do a bunch of run-time reformatting to make it all work. This seems like a lot of extra work. Am I doing this in a totally stupid way? Is there some "obvious" easier way of doing this that I'm missing?
A tidier way is to create separate forms for each 'pane' and, in each form constructor, set
this.TopLevel = false;
this.FormBorderStyle = FormBorderStyle.None;
this.Dock = DockStyle.Fill;
That way, each of these forms can be laid out in its own designer, instantiated one or more times at runtime, and added to the empty area like a normal control.
Perhaps the main form could use a SplitContainer with a static TreeView in one panel, and space to add these forms in the other. Once they are added, they could be flipped through using Hide/Show or BringToFront/SendToBack methods.
SeparateForm f = new SeparateForm();
MainFormSplitContainer.Panel2.Controls.Add(f);
f.Show();
Greg Hurlman wrote:
Why not just show/hide the proper container when a node is selected in the grid? Have the containers all sized appropriately in the same spot, and hide all but the default, which would be preselected in the grid on load.
Unfortunately, that's what I'm trying to avoid. I'm looking for an easy way to handle the interface during design time, with minimal reformatting code needed to get it working during run time.
I like Duncan's answer because it means the design of each node's interface can be kept completely separate. This means I don't get overlap on the snapping guidelines and other design time advantages.
I would probably create several panel classes based on a base class inheriting CustomControl. These controls would then have methods like Save/Load and stuff like that. If so I can design each of these panels separately.
I have used a Wizard control that in design mode, handled several pages, so that one could click next in the designer and design all the pages at once through the designer. Though this had several disadvantages when connecting code to the controls, it probably means that you could have a similar setup by building some designer classes. I have never myself written any designer classes in VS, so I can't say how to or if its worth it :-)
I'm a little curious of how you intend to handle the load/save of values to/from the controls? There must be a lot of code in one class if all your pages are in one big Form?
And yet another way would of course be to generate the gui code as each page is requested, using info about what type of settings there are.

Categories