dotnet / dotnet/winforms

Introduce `ControlExtensions` to simplify frequently needed iterating tasks

Open
#12,543 3 comments 1 reaction 1 assignee Claimed by @KlausLoeffelmann View on GitHub
:construction: work in progress api-suggestion
Dominant language
C#
Stars
4.9k
Forks
1.1k
Avg merge
20h 23m
Merged PRs (30d)
103

Description

### Background and motivation

There are a lot of cases, where we need to recursively traverse through the controls collection (up or down), to either process a collection of certain controls or find a specific control in the tree. This is, where the typical WinForms developer invents the wheel for their apps for the gazilion-th time.

To that end, we suggest introducing the following extension class to make those tasks super-convenient, and make sure, that we do not allocate anything during operation.

Note:
PR would be a side-product of one of the .NET Conf Demos and ready to go immediately.
@merriemcgaw, @lonitra

@JeremyKuhne: If we want to further discuss the concept of a more granular base-layout type, this API would be super-easy to adapt to that and also the perfect icing on that cake.

### API Proposal

```csharp
public static IEnumerable ChildControls(this Control control)
public static IEnumerable ChildControls(this Control control) where T : Control
public static Control FirstChild(this Control control, Func? predicate = default)
public static T FirstChild(this Control control, Func? predicate = default) where T : Control
public static T? FirstChildOrDefault(this Control control, Func? predicate = default) where T : Control
public static IEnumerable AscendantControls(this Control control)
public static IEnumerable AscendantControls(this Control control, Func? predicate = default) where T : Control
public static Control FirstAscendant(this Control control, Func? predicate = default)
public static Control? FirstAscendantOrDefault(this Control control, Func? predicate = default)
public static T FirstAscendant(this Control control, Func? predicate = default) where T : Control
public static T? FirstAscendantOrDefault(this Control control, Func? predicate = default) where T : Control
public static IEnumerable DescendantControls(this Control control)
public static IEnumerable DescendantControls(this Control control, Func? predicate = default) where T : Control
public static Control FirstDescendant(this Control control, Func? predicate = default)
public static T FirstDescendant(this Control control, Func? predicate = default) where T : Control
public static Control? FirstDescendantOrDefault(this Control control, Func? predicate = default)
public static T? FirstDescendantOrDefault(this Control control, Func? predicate
public static Control Root(this Control control)
```

### API Usage

Self-Explaining.

### Alternative Designs

_No response_

### Risks

None.

### Will this feature affect UI controls?

Only easier usage and help with discoverability.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.